Exception Link Exception Using F #

Is there a way to make the following code work?

open System.Collections.Generic type Geometry<'t>(child: 't) = let values = List() member o.add (v: float) = values.Add v; child and Line() as self = inherit Geometry<Line>(self) member o.length v = o.add v let line = Line().length(50.0) 

I get

System.NullReferenceException: An object reference is not set to an object instance.

EDIT:

It is enough to call the following to throw an exception.

 let line = Line() 

The motivation is what you can do, for example:

 let line = Line().x1(10).y1(20).x2(30).y2(10).color("blue") // ... 

and you can reuse common elements among all geometries (circle, ellipse, ...)

+4
source share
3 answers
 open System.Collections.Generic type Geometry<'t when 't :> Geometry<'t>>() = let values = List() member o.add (v: float) = values.Add v; o :?> 't and Line() = inherit Geometry<Line>() member o.length v = o.add v let line = Line().length(50.0) 
+5
source

In .NET (and with the extension F #), you need to initialize an object before you can call any method on it or pass it to another method. Thus, your Line object must be initialized before it is passed to the base Geometry<Line>(self) constructor. But it cannot be initialized before the base constructor is called, so there is no direct way to do what you want.

Having said that, F # has a system that must catch illegal recursive values ​​of values ​​before they are determined, so I am surprised that you will not get a more meaningful exception instead of a NullReferenceException (or better, but a compile-time error). Compare, for example, what happens if you try to call new Rec() with the following definition:

 type Rec(r:Rec) = new() as self = Rec(self) 

One way to solve this problem is to use laziness to delay the use of the self identifier:

 type Geometry<'t>(child: Lazy<'t>) = let values = List() member o.add (v: float) = values.Add v; child.Value and Line() as self = inherit Geometry<Line>(lazy self) member o.length v = o.add v 

Unfortunately, this will not work, giving even more importance to the theory that in this case there is an F # error with checking the reliability of initialization. Fortunately, this can be circumvented by using the explicit constructor for Line instead of the main constructor:

 type Geometry<'t>(child: Lazy<'t>) = let values = List() member o.add (v: float) = values.Add v; child.Value and Line = inherit Geometry<Line> new() as self = { inherit Geometry<Line>(lazy self) } member o.length v = o.add v 
+3
source

One note about F # - one of the main functions - it is very brief (especially compared to C # or Java). In my experience, however, it is also easy to get carried away trying to make your code as concise as possible; instead, you will be better off writing code that is as concise as possible.

The reason I explain this is because you use a semicolon to place several statements on the same line - this makes the code shorter by keeping one or two lines of the new line, but the disadvantage is that it does not play well with VS debugger

If you remove the use of semicolons, you can place breakpoints on the corresponding lines and then go through them using the VS debugger (or MonoDevelop / Xamarin Studio). Understanding which operator is causing the exception makes it much easier to determine the cause of the problem.

If you try this and can determine this line, add this information to your question and we can give you a better answer.

 type Geometry<'t> (child: 't) = let values = ResizeArray () member o.add (v: float) = values.Add v child and Line () as self = inherit Geometry<Line> (self) member o.length v = o.add v let line = let l = Line () l.length 50.0 
+1
source

Source: https://habr.com/ru/post/1479042/


All Articles