Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand F# class definition syntax

I'm approaching now to F# classes after learning a lot about the most important features of this language. Well, the class definition syntax is not simple to understand, but some of the main concepts are now clear to me, but others do not.

1) The first thing I would like to know is just a CORRECT/NOT CORRECT. I understood that classes can be defined in two ways:

  • Implicit classes. These classes have one constructor only, and in the first lines of the class, it is necessary to define, using the let binding, all internal variables assigning them a value.
  • Explicit classes. These classes have many constructors. They accept, through the val binding, non-initialized values. These values MUST ALL BE INITIALIZED in constructors. If a constructor fails defining a value for at least one of the private variables defined using the val binding, the compiler will get mad.

IS IT CORRECT???

2) I have a problem understanding the syntax for the constructor in explicit classes. Consider the following:

Here's the first version:

(* COMPILES :) *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = {
      myval = a;
      myother = b;
   }

Here's the second version:

(* COMPILES :) *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = {
      myval = a (* No semicolon *)
      myother = b (* No semicolon *)
   }

Here's the last version:

(* DOES NOT COMPILE :( *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = 
      myval = a (* Using the normal indent syntax, without {} *)
      myother = b (* Using the normal indent syntax, without {} *)

I do not understand why the first two versions compile and the third, that uses the regular indentation syntax, does not. This problem occurs only in constructors because on members I can use the indent syntax

(* COMPILES :) *)
type MyType =
   val myval: int
   val myother: int
   (* Constructor *)
   new (a: int, b: int) = {
      myval = a (* No semicolon *)
      myother = b (* No semicolon *)
   }
   (* Indentation accepted, no {} to be inserted *)
   member self.mymember =
      let myvar = myval
      myvar + 10

Why the new function (the constructor) needs {} brackets????? I do not like it, because it seems that a sequence is considered. Furthermore, my code compiles also when, in the {} rackets, between one instruction and the other, no semicolon is inserted. WHY????

like image 758
Andry Avatar asked Feb 11 '11 19:02

Andry


People also ask

What does changing f-stop?

Changing the f-number changes the size of the aperture, changing the amount of light that passes through the lens. The higher the f-number, the smaller the aperture and the less light that passes through the lens; the lower the f-number, the larger the aperture and the more light that passes through the lens.

What does low f mean?

How Aperture Affects Shutter Speed. Using a low f/stop means more light is entering the lens and therefore the shutter doesn't need to stay open as long to make a correct exposure which translates into a faster shutter speed.

At what f-stop is everything in focus?

F22 aperture creates a photo with all parts in focus, from elements close to the camera to subject matter far away in the background. This phenomenon is known as a wide depth of field — it's the opposite of photos where the background is blurred and an object is in focus.

How do I know which f-stop to use?

The f-stop number is determined by the focal length of the lens divided by the diameter of the aperture. Focal length refers to a lens' field of view (sometimes called angle of view), which is the width and height of the area that a particular lens can capture.


2 Answers

You wrote (emphasis mine):

Implicit classes. These classes have one constructor only, and in the first lines of the class, it is necessary to define, using the let binding, all internal variables assigning them a value.

That's not actually true - you can use the implicit syntax to define class with multiple constructors. In fact, I think it is a good idea to use the implicit class syntax almost always (because it makes declarations simpler). Implicit classes have one primary constructor which is the one you get implicitly - this constructor should take the largest number of parameters (but it can be private):

type Foo(a:int, b:int) =
  do printfn "hello"         // additional constructor code
  member x.Multiple = a * b  // some members
  new(x:int) = Foo(x, x)     // additional constructor

To make the constructor private, you can write

type Foo private (a:int, b:int) =
  ...

Then you can use the primary constructor just as a nice way to initialize all the fields.

like image 91
Tomas Petricek Avatar answered Nov 09 '22 21:11

Tomas Petricek


Regarding 2), the body of a constructor is not like the body of a typical function - it has a restricted syntactic form, and within the { } section it can only contain a call to the parent constructor and assignments of fields (similar to record construction). When defining a normal member you can't wrap the individual expressions in { } even if you wanted to (that is, the braces are not optional in this context, they are forbidden).

like image 39
kvb Avatar answered Nov 09 '22 20:11

kvb