caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Gerd Stolpmann <gerd@gerd-stolpmann.de>
To: Gregoire Sutre <sutre@eecs.berkeley.edu>, caml-list@inria.fr
Subject: Re: [Caml-list] Open class type definition ?
Date: Mon, 23 Apr 2001 20:21:56 +0200	[thread overview]
Message-ID: <01042321362504.02753@ice> (raw)
In-Reply-To: <3AE2538F.83A03652@eecs.berkeley.edu>

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


      reply	other threads:[~2001-04-24  7:11 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-04-22  3:44 Gregoire Sutre
2001-04-23 18:21 ` Gerd Stolpmann [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=01042321362504.02753@ice \
    --to=gerd@gerd-stolpmann.de \
    --cc=caml-list@inria.fr \
    --cc=sutre@eecs.berkeley.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).