The following does not require the #light tag.

The second function allows you to construct an object whose methods can refer to other methods.

1
2
3
4
5
6
7
8
9
10
11
12
13
 

type A () =
  class
    abstract run : unit -> unit
    abstract run' : int-> unit
  end

let make_a () = {new A() with run() = () and run' x = () }

let make_a_bis () = {new A() as self with run() = () and run' x = self.run() }

let a_object = {new A() with run() = print_string "I am an A object" and run' x = ()  }

see [link:research.microsoft.com] for more details on object expressions...

Hope this helps

By on 11/21/2007 3:00 AM ()
1
2
3
4
5
6
7
8
9
//#light

type mm = class 
  new () = {} 
  abstract min : int 
  abstract max : int 
end

let x = {new mm() with member self.min = 1 member self.max = 1 end }

hth

By on 11/21/2007 7:31 AM ()

Hello.

Thank you for the corrections; you two help me out.
I have been comparing the two notations;
indeed they do not look synonyms observed by the following experiment:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
type a = class 
  new () = {}
  abstract f : (int -> int)
end;;

(* only x3 works *)
let x1 = { new a () with f x = x };;
let x2 = { new a () with f = fun x -> x };;
let x3 = { new a () with member self.f = fun x -> x  end};;
let x4 = { new a () with member self.f x = x  end};;

type b = class 
  new () = {}
  abstract f : int -> int
end;;

(* only y3 does NOT work *)
let y1 = { new b () with f x = x };;
let y2 = { new b () with f = fun x -> x };;
let y3 = { new b () with member self.f = fun x -> x  end};;
let y4 = { new b () with member self.f x = x  end};;

I am afraid that I do not well-understand the differences
between methods and properties...

Best,

keiko

By on 11/22/2007 2:04 AM ()

Hi Keiko,

Properties are a .NET notion that map to one or both of a get_X() and set_X() method. While a method and a function-valued-get-only-property look, for all practical purposes, similar, they are not identical. For example, you can overload between methods, but you can't have multiple function-valued-properties with the same name.

FWIW function-valued-get-only-properties basically never arise in practice: programmers would typically always normalize these to method definitions, just as a C# programmer would essentially never have a get-only property of type Func<int,int>.

The object expression form { new ... with a = ... and b = ... } can, for the purposes of this discussion, be considered deprecated. It was the original object expression form in the language, before F# supported OO programming. It has a number of problems, which are perfectly highlighted here:

  • Specifying values for properties was not possible. Well, it is possible, if you use a workaroud such as { new a () with get_f() = (fun x -> x) }, but that's a hack known only to .NET afficianados.
  • The syntax doesn't require an "end" in #light mode, which looks odd.
  • The syntax gives no way for members to recursively refer to the object
  • The syntax is not uniform with the syntax used for members in class definitions.

As a result the object expression syntax that uses "members" is greatly preferred. While the original syntax has not been deprecated as yet, it is clearly a candidate for doing so in a future revision of the language.

Once this is taken into account, the results above look better: members are specified using

1
   member self.f x = expr

and (get-only) properties specified using

1
member self.f = expr

Kind regards

Don

By on 11/22/2007 8:31 AM ()

Thank you for the detailed explanation.

I prefer to use "members" syntax; I like the explicit self-reference.

Just a tiny remark.

Having been programming with OCaml, I have got used to

indiscriminately mix two ways of defining pattern matching functions, e.g.,

1
 let f x = match x with A -> 1 | B -> 2

and

1
 let f = function A -> 1 | B -> 2

But this does not look a good habit, observing this behavior:

1
2
3
4
5
6
7
8
9
type t = A | B
type c1 = class
 new () = {}
 abstract f : t -> int
 default self.f x = match x with A -> 1 | B -> 2

(* the following is not available *)
(* default self.f = function A -> 1 | B -> 2 *)
end

Probably I should stick to the "match x with" idiom,

which would also improve the uniformity of my program code.

By the way, I just noticed the following typing behavior:

1
2
let h1 x = match x with A -> 1 | B -> 2
let h2 x = 1

The inferred types:

1
2
  val h1 : 'a -> int
  val h2 : 'a -> int

Note that I did not declare the value constructors A or B.
I think, despite the same appearance, the two types have distinct meanings;
the latter means "for all", the former may mean "exists".
(But I prefer the former ill-typed.)

Best,

keiko

By on 11/23/2007 5:09 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper