On Sun, May 31, 2009 at 7:08 PM, Dario Teixeira <darioteixeira@yahoo.com> wrote:
I also meant "heavier" in terms of efficiency. And like David said, it does
feel wrong to carry the performance penalty of the object system solely because
I need the structural subtyping features.
If you're willing to give up some of the syntactic niceties of records (and the ability to pattern-match) you can get what you want using an abstract type.
module type S = sig
type 'a t
val create_t1 : a : int -> b : int -> c : int -> [ `a | `b | `c ] t
val create_t2 : a : int -> b : int -> c : int -> d : int
-> [ `a | `b | `c | `d ] t
val create_t3 : b : int -> c : int -> d : int -> [ `b | `c | `d ] t
val a : [> `a ] t -> int
val b : [> `b ] t -> int
val c : [> `c ] t -> int
val d : [> `d ] t -> int
end
module M : S = struct
type u = { a: int; b: int; c :int; d: int }
type 'a t = u
let default = { a = 0; b = 0; c = 0; d = 0 }
let create_t1 ~a ~b ~c = { default with a = a; b = b; c = c }
let create_t2 ~a ~b ~c ~d = { a = a; b=b; c=c; d=d; }
let create_t3 ~b ~c ~d = { default with b=b; c=c; d=d }
let a t = t.a
let b t = t.b
let c t = t.c
let d t = t.d
end
let f x = M.a x + M.b x
let g () = f (M.create_t1 ~a:0 ~b:0 ~c:0) (* accepted by compiler *)
let g () = f (M.create_t2 ~a:0 ~b:0 ~c:0 ~d:0) (* accepted by compiler *)
let g () = f (M.create_t3 ~b:0 ~c:0 ~d:0) (* rejected by compiler *)
The compiler error you get on that last line is this:
Error: This expression has type [ `b | `c | `d ] M.t
but is here used with type [> `a | `b ] M.t
The first variant type does not allow tag(s) `a
Here, we've chosen to use a default value for fields that we don't fill in. We could just as well have used options here. The performance of the above will be roughly the same as the performance of a simple record. Obviously, all of the different "subtypes" have the full record stored at a physical level.
y