Andry
Andry

Reputation: 16895

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:

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????

Upvotes: 6

Views: 714

Answers (2)

Tomas Petricek
Tomas Petricek

Reputation: 243096

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.

Upvotes: 3

kvb
kvb

Reputation: 55185

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).

Upvotes: 2

Related Questions