Version française
Home     About     Download     Resources     Contact us    
Browse thread
[Caml-list] Functors and classes
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: John Prevost <j.prevost@g...>
Subject: Re: [Caml-list] Functors and classes
GOT IT!

The trick is to provide a cast operation from the original module,
which can then be used by the functor.  The functor gets grumpy
because it doesn't have enough information (or perhaps smarts) to be
sure the type can be unified.  But the original creator surely does.

Find below the complete source--I separated things up in some
semblance of the modules you'd expect to find in wild .ml and .mli
files, just to be sure that doesn't break anything.  :)

The best part is that even though the functor has to go through "toss"
to get to the known methods of a connection, the module that uses the
functor knows the full identity of the type, and can access all
methods (and use other functions that work on the type) of the
original object--preserving extensibility.


module Things =                         (* Things.ml *)
  (struct
    class type base_connection =
      object
        method a : int
      end

    module type Thing_T =
      sig
        type connection
        val connect : unit -> connection
        val toss : connection -> base_connection
      end

    module type Thing_Pool_T =
      sig
        type connection
        val connect : unit -> connection
        val test : connection -> int
      end

    module Thing_Pool (Thing : Thing_T) :
        Thing_Pool_T with type connection = Thing.connection =
      struct
        type connection = Thing.connection
        let connect () = Thing.connect ()
        let test c = (Thing.toss c)#a + 1
      end
  end : sig                             (* Things.mli *)
    class type base_connection =
      object
        method a : int
      end

    module type Thing_T =
      sig
        type connection
        val connect : unit -> connection
        val toss : connection -> base_connection
      end

    module type Thing_Pool_T =
      sig
        type connection
        val connect : unit -> connection
        val test : connection -> int
      end

    module Thing_Pool : functor (Thing : Thing_T) ->
      Thing_Pool_T with type connection = Thing.connection
  end)

(* database package to be pooled *)

module Thing_Test =                     (* Thing_Test.ml *)
  (struct
    class connection =
      object
        method a = 1
        method b = 2
      end
    let connect () = new connection
    let toss c = (c :> Things.base_connection)
  end : sig                             (* Thing_Test.mli *)
    class connection :
      object
        method a : int
        method b : int
      end
    val connect : unit -> connection
    val toss : connection -> Things.base_connection
  end)

(* package using the pool *)

module Program =                        (* Program.ml *)
  struct
    open Things
      
    module X = Thing_Pool(Thing_Test)
        
    let x = X.connect ()
    let a = x#a
    let b = x#b
  end

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners