views:

188

answers:

3

I am attempting to simulate an interface in OCaml and am using the "type" construct. I have two types:

type fooSansBar = {a: string; b: int};;
type fooConBar = {a:string; b:int; bar:char};;

...and would like to define a particular fooSansBar:

let fsb = {a="a"; b=3};;

...but am told that the bar field is not defined. From this, it appears that, contrary to the values I passed in matching fooSansBar's signature, the system believes I am trying to create a fooConBar. Is it possible to create a fooSansBar if the two types as defined above exist?

Additionally (because I'm new to OCaml) is there a better way to simulate an interface?

+2  A: 

The second type redefines a and b, effectively hiding the first, which is why it cannot be constructed any more. You could define these types in different modules, but that would be the same as using a different name for a and b.

These constructs can only be used when you do not try to "derive" from another interface, but just implement it.

If you wish to use these object oriented concepts in Ocaml, you could look at the object system, or, depending on your problem, the module system. Alternatively, you could try to solve your problem in a functional way. What problem are you trying to solve?

small_duck
+5  A: 

In OCaml, field names in record types must be unique, so the two types you define cannot coexist simultaneously. Caml is the only language I know with this property.

Because the second definition hides the first, when the compiler sees the a and b fields it expects them to belong to the fooConBar type and so complains of the missing bar field.

If you are trying to simulate an interface, the correct functional way to do it in Caml is to define a module type.

module type FOO_CON_BAR = sig
  val a : string
  val b : int
  val bar : char
end

And an instance:

module Example = struct
  let a = "hello"
  let b = 99
  let c = '\n'
end

With modules and module types you also get subtyping; there's no need to resort to objects.

P.S. My Caml is rusty; syntax may be off.

Norman Ramsey
+2  A: 

There are several possible solutions in OCaml depending how you're using the code you gave. The simplest is to combine the two types:

type fooBar = { a: string; b: int; bar: char option }

Another solution is to replace the records with objects because objects support subtyping (and can have their types inferred so there is no need to declare a type!):

# let fsb = object
    method a = "a"
    method b = 3
  end;;
val fsb : < a : string; b : int > = <obj>

# fsb#a, fsb#b;;
- : string * int = ("a", 3)
Jon Harrop