Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] Open class type definition ?
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Gerd Stolpmann <gerd@g...>
Subject: Re: [Caml-list] Open class type definition ?
On Sun, 22 Apr 2001, Gregoire Sutre wrote:
>Hi,
>
>I'm trying to use the Object model of OCaml and I'm having trouble with the
>class types.
>
>My goal is to have datatypes that can be easily converted into strings for
>debugging purposes.  So instead of enclosing each datatype inside a
>dedicated module with a to-string() function (that would lead to a huge
>number of modules), I thought that I could use an object type instead,
>saying that there is *at least* a method to_string(), and define my
>datatypes as classes with *at least* a to_string() method inside each class.
>
>For instance, I could specify an ordered type this way:
>
>module type ORDERED_TYPE =
>  sig
>    type t = < to_string : unit -> string >
>    val compare : t -> t -> int
>  end

This module type is already problematic. The O'Caml types are very strict, and
this definition of 'compare' means that the function can only call the
to_string method, and nothing more.

[...]
>module Funct(A : ORDERED_TYPE) =
>  struct
>    let display_cmp x y = x#to_string() ^ " cmp " ^ x#to_string() ^
>                          " = " ^ (string_of_int (A.compare x y))
>  end
[...]
>
>module Foo =
>  struct
>    class my_int x =
>      object
>        val mutable v = x
>        method to_string () = "Int(" ^ (string_of_int v) ^")"
>        method get_v = v
>        method set_v new_v = v <- new_v
>      end
>
>    type t = my_int
>    let compare (x:t) (y:t) = compare x#get_v y#get_v
>  end
>
>In this module, the compare function reads the integer value stored in the
>objects to perform its job.  But then, the type t of the Foo module does not
>correspond to the type t of the ORDERED_TYPE signature and I can not apply
>the functor to Foo:
>
>[...]
>Type declarations do not match:
>  type t = my_int
>is not included in
>  type t = < to_string : unit -> string >

The problem is that subtyping is not allowed when the compiler checks whether
an implementation matches a signature. (Can somebody of the experts explain
this?) Declaring t with an ellipsis ("..") does change nothing, because even
if the compiler accepted t =  to_string : unit -> string; ..> it would be still
necessary that the subtyping relation t :> my_int holds.

So the consequences for program design are:
 - Use classes when subclassing and/or subtyping is needed
 - Use functors when information hiding is more important
 - Do not mix both concepts in the sense that applying a functor bases on a
   subtyping relation

The possible solutions for your concrete problem:

(1) Prefer classes:

module type ORDERED_TYPE =  sig
  class type t = 
    object 
       method to_string : unit -> string 
       method compare : t -> int
    end
end

(2) Accept that the class t is only a "vehicle" for a certain effect, and make
the method get_v accessible:

module type ORDERED_TYPE =  sig
  class type ['a] t = 
    object 
       method to_string : unit -> string 
       method get_v : 'a
    end
end

(3) Consider also the following solution without classes: (similar to (2))

module type ORDERED_TYPE =  sig
  type t_base
  type t = { to_string : unit -> string; v : t_base }
  val compare : t -> t -> int
end

module Foo =  struct
  type t_base = int
  type t = { to_string : unit -> string; v : t_base }
  let make n = 
    { to_string = (fun () -> "Int(" ^ string_of_int n ^ ")");
      v = n;
    }
  let compare (x:t) (y:t) = compare x.v y.v
end

module Funct(A : ORDERED_TYPE) =
struct
  let display_cmp x y = x.A.to_string() ^ " cmp " ^ y.A.to_string() ^
  " = " ^ (string_of_int (A.compare x y))
end

I have also a fourth solution, but I do not recommend it: Misuse polymorphic
variants to tag the type explicitly, and use a central to_string like

let to_string x =
  match Obj.magic x with
    `Int n -> Int(" ^ string_of_int n ^ ")"
   | ... other cases ...

This is unsafe, and you will get segfaults if type passed to to_string is not
any of the enumerated variants. 

Gerd
-- 
----------------------------------------------------------------------------
Gerd Stolpmann      Telefon: +49 6151 997705 (privat)
Viktoriastr. 100             
64293 Darmstadt     EMail:   gerd@gerd-stolpmann.de
Germany                     
----------------------------------------------------------------------------
-------------------
To unsubscribe, mail caml-list-request@inria.fr.  Archives: http://caml.inria.fr