caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Functors and classes
@ 2004-08-03 12:02 Richard Jones
  2004-08-03 12:10 ` Richard Jones
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Jones @ 2004-08-03 12:02 UTC (permalink / raw)
  To: caml-list


I'm trying to replace the current mod_caml approach to pooling
database handles with a functorized one.  However there seems to be
some problem with the way functors and classes interact.

I have a hierarchy of classes:

      Dbi.connection
           |
           ^
           |
   +----------- - - - etc.
   |
 Dbi_postgres.connection

I'd like to create a pool of "postgres connections" using something
like:

  module MyPool = Apache.DbiPool (Dbi_postgres)

So far, the apache.mli looks like below.  It doesn't compile because:

  Unbound type constructor DbiConnection.connection

at the last line.

Is this sort of thing even possible?

Rich.

------------------------------------------------------- apache.mli ---------
module type DbiConnection = sig

  class connection : ?host:string -> ?port:string ->
			      ?user:string -> ?password:string -> string ->
  object
    method close : unit -> unit
    method closed : bool
    method ping : unit -> bool
    method rollback : unit -> unit
  end

end

module type DbiPoolT = sig

  type connection

  val get : Request.t -> ?host:string -> ?port:string ->
    ?user:string -> ?password:string -> string -> connection
end

module DbiPool (Dbi : DbiConnection) : DbiPoolT
  with type connection = DbiConnection.connection
----------------------------------------------------------------------

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
MAKE+ is a sane replacement for GNU autoconf/automake. One script compiles,
RPMs, pkgs etc. Linux, BSD, Solaris. http://www.annexia.org/freeware/makeplus/

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 12:02 [Caml-list] Functors and classes Richard Jones
@ 2004-08-03 12:10 ` Richard Jones
  2004-08-03 13:17   ` Richard Jones
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Jones @ 2004-08-03 12:10 UTC (permalink / raw)
  To: caml-list

On Tue, Aug 03, 2004 at 01:02:44PM +0100, Richard Jones wrote:
>   Unbound type constructor DbiConnection.connection

Sorry, please ignore that.  I realised there was a very stupid typo in
that last line (should be Dbi.connection, not
DbiConnection.connection).

> module DbiPool (Dbi : DbiConnection) : DbiPoolT
>   with type connection = DbiConnection.connection

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
http://www.YouUnlimited.co.uk/ - management courses

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 12:10 ` Richard Jones
@ 2004-08-03 13:17   ` Richard Jones
  2004-08-03 15:06     ` John Prevost
  0 siblings, 1 reply; 13+ messages in thread
From: Richard Jones @ 2004-08-03 13:17 UTC (permalink / raw)
  To: caml-list

OK, I have another problem.

My apache.mli now looks like this:

----------------------------------------------------------------------
module type DbiConnection = sig

  class connection : ?host:string -> ?port:string ->
			      ?user:string -> ?password:string -> string ->
  object
    method close : unit -> unit
    method closed : bool
    method ping : unit -> bool
    method rollback : unit -> unit
  end

end

module type DbiPoolT = sig

  type connection

  val get : Request.t -> ?host:string -> ?port:string ->
    ?user:string -> ?password:string -> string -> connection
end

module DbiPool (Dbi : DbiConnection) : DbiPoolT
  with type connection = Dbi.connection
----------------------------------------------------------------------

This compiles fine, with the corresponding .ml file.  However when
I try to instantiate a pool using:

module Pool = DbiPool (Dbi_postgres)

I get errors:

File "examples/useful-scripts/maillist.ml", line 49, characters 23-35:
Signature mismatch:
Modules do not match:
[...]
The public method commit cannot be hidden
The public method database cannot be hidden
The public method database_type cannot be hidden
[etc.]

I understand why this happens, because the actual Dbi_postgres.-
connection class is much more complicated than the mere four methods
which I need to use to make the pool work.

However, importing the entire class type is complex in three respects:
it depends on a bunch of other classes which need to be imported; and
it means that a particular version of mod_caml becomes very dependent
on a particular version of ocamldbi; and (crucially, fatally) the
different database subclasses may all contain extra and different
public methods, so there is no way to list all the public methods
anyway.

I tried to define an "open class" (<method; method; ..>) using:

module type DbiConnection = sig

  class connection : ?host:string -> ?port:string ->
			      ?user:string -> ?password:string -> string ->
    < close : unit -> unit;
      closed : bool;
      ping : unit -> bool;
      rollback : unit -> unit; .. >

end

but this gives a syntax error.

Ideas on how to solve this one?

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
NET::FTPSERVER is a full-featured, secure, configurable, database-backed
FTP server written in Perl: http://www.annexia.org/freeware/netftpserver/

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 13:17   ` Richard Jones
@ 2004-08-03 15:06     ` John Prevost
  2004-08-03 15:12       ` Richard Jones
  2004-08-03 15:50       ` Richard Jones
  0 siblings, 2 replies; 13+ messages in thread
From: John Prevost @ 2004-08-03 15:06 UTC (permalink / raw)
  To: Ocaml Mailing List

The following model works for me.  The key problem here is that
there's no way to bring a class binding in in the way you want. 
That's not really a problem, except that you lose the ability to call
"new".  Perhaps the Dbi interface could be changed to allow for this? 
(Depending on how you do things, this could mean that a DbiPool could
itself be used as a Dbi module, somehow.)

It's also possible that I'm missing some way to otherwise do this.

John.


module TestThing =
  struct
    class connection =
      object
        method a = 1
	method b = 1
	method c = 1
      end
    let connect () = new connection
  end

module type ThingIntf = 
  sig
    type connection
    val connect : unit -> connection
  end

module type ThingPoolT =
  sig
    type connection
    val connect : unit -> connection
  end

module ThingPool (Thing : ThingIntf) :
    (ThingPoolT with type connection = Thing.connection) =
  struct
    type connection = Thing.connection
    let connect () = Thing.connect ()
  end

module X = ThingPool(TestThing)

let x = X.connect ()

let a = x #a
let b = x #b
let c = x #c

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 15:06     ` John Prevost
@ 2004-08-03 15:12       ` Richard Jones
  2004-08-03 15:27         ` John Prevost
  2004-08-03 15:50       ` Richard Jones
  1 sibling, 1 reply; 13+ messages in thread
From: Richard Jones @ 2004-08-03 15:12 UTC (permalink / raw)
  To: John Prevost; +Cc: Ocaml Mailing List

On Tue, Aug 03, 2004 at 11:06:33AM -0400, John Prevost wrote:
> The following model works for me.  The key problem here is that
> there's no way to bring a class binding in in the way you want. 
> That's not really a problem, except that you lose the ability to call
> "new".  Perhaps the Dbi interface could be changed to allow for this? 
> (Depending on how you do things, this could mean that a DbiPool could
> itself be used as a Dbi module, somehow.)

> module type ThingIntf = 
>   sig
>     type connection
>     val connect : unit -> connection
>   end

Thanks.  I understand what you're getting at here, and it kind of
reflects the way that lablgtk hides the 'new' operator too, although
I'm not sure if that's for the same reasons.  Looks like a
backwards-compatible change to the Dbi module interfaces is required.

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
"One serious obstacle to the adoption of good programming languages is
the notion that everything has to be sacrificed for speed. In computer
languages as in life, speed kills." -- Mike Vanier

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 15:12       ` Richard Jones
@ 2004-08-03 15:27         ` John Prevost
  2004-08-03 15:28           ` John Prevost
  0 siblings, 1 reply; 13+ messages in thread
From: John Prevost @ 2004-08-03 15:27 UTC (permalink / raw)
  To: Ocaml Mailing List

On Tue, 3 Aug 2004 16:12:41 +0100, Richard Jones <rich@annexia.org> wrote:
> Thanks.  I understand what you're getting at here, and it kind of
> reflects the way that lablgtk hides the 'new' operator too, although
> I'm not sure if that's for the same reasons.  Looks like a
> backwards-compatible change to the Dbi module interfaces is required.

Actually, there's another issue.  The row type defining the methods is
visible from outside the functor, but not from inside.  I'm... er...
not sure how to solve this one.  If nobody else has answered, I'll
fiddle some more this evening when I'm done with work.

John.


Example of what causes the compile to fail (using one of the methods
we want to see):

module type ThingPoolT =
  sig
    type 'a connection
    val connect : unit -> connection
    val test : connection -> unit
  end

module ThingPool (Thing : ThingIntf) :
    (ThingPoolT with type connection = Thing.connection) =
  struct
    type connection = Thing.connection
    let connect () = Thing.connect ()
    let test x = x#a + 1 
  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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 15:27         ` John Prevost
@ 2004-08-03 15:28           ` John Prevost
  2004-08-03 19:57             ` brogoff
  0 siblings, 1 reply; 13+ messages in thread
From: John Prevost @ 2004-08-03 15:28 UTC (permalink / raw)
  To: Ocaml Mailing List

Oops.  A couple of errors in that last thing I wrote that weren't the
problem I was trying to illustrate (that's what I get for trying fixes
inline before giving up):

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

module ThingPool (Thing : ThingIntf) :
    (ThingPoolT with type connection = Thing.connection) =
  struct
    type connection = Thing.connection
    let connect () = Thing.connect ()
    let test x = x#a + 1 
  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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 15:06     ` John Prevost
  2004-08-03 15:12       ` Richard Jones
@ 2004-08-03 15:50       ` Richard Jones
  2004-08-03 16:23         ` John Prevost
  1 sibling, 1 reply; 13+ messages in thread
From: Richard Jones @ 2004-08-03 15:50 UTC (permalink / raw)
  To: John Prevost; +Cc: Ocaml Mailing List

On Tue, Aug 03, 2004 at 11:06:33AM -0400, John Prevost wrote:

I've found a problem with this approach.  If I replace the connect
function here:

> module ThingPool (Thing : ThingIntf) :
>     (ThingPoolT with type connection = Thing.connection) =
>   struct
>     type connection = Thing.connection
>     let connect () = Thing.connect ()
>   end

with:

  let connect () =
    let conn = Thing.connect () in
    ignore (conn#a);
    conn

then I get the following error:

  File "test.ml", line 30, characters 14-18:
  This expression has type Thing.connection
  It has no method a

So I extended the type of connection as follows to make it work:

  module type ThingIntf =
    sig
      type connection = <a : int; b : int; c : int>
      val connect : unit -> connection
    end

That's all well and good.  BUT I need to define something more like
this:

  module type ThingIntf =
    sig
      type connection = <a : int; ..>
      val connect : unit -> connection
    end

which gives me:

  File "test.ml", line 14, characters 8-35:
  A type variable is unbound in this type declaration

(I'm only uses a small subset of the much larger interface in my
pooling code).

Full code which fails is attached.

Thanks,

Rich.

----------------------------------------------------------------------
module TestThing =
  struct
    class connection =
    object
      method a = 1
      method b = 1
      method c = 1
    end
    let connect () = new connection
  end

module type ThingIntf =
  sig
    type connection = <a : int; ..>
    val connect : unit -> connection
  end

module type ThingPoolT =
  sig
    type connection
    val connect : unit -> connection
  end

module ThingPool (Thing : ThingIntf) :
    (ThingPoolT with type connection = Thing.connection) =
  struct
    type connection = Thing.connection
    let connect () =
      let conn = Thing.connect () in
      ignore (conn#a);
      conn
  end

module X = ThingPool(TestThing)

let x = X.connect ()

let a = x #a
let b = x #b
let c = x #c
----------------------------------------------------------------------

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
If I have not seen as far as others, it is because I have been
standing in the footprints of giants.  -- from Usenet

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 15:50       ` Richard Jones
@ 2004-08-03 16:23         ` John Prevost
  2004-08-03 16:42           ` Richard Jones
  0 siblings, 1 reply; 13+ messages in thread
From: John Prevost @ 2004-08-03 16:23 UTC (permalink / raw)
  To: Ocaml Mailing List

Yes, that's the same problem I'm seeing.  I think it *might* be
possible to get around it by using a connection type with type
parameters.  Maybe.  I'll investigate more in a few hours.

This is an upsetting problem, but I believe that it's known that there
are some drawbacks to mixing classes and functors.  (And, well, if
it's not, it should be now.)  Anyway, we'll see what can be done.

If one of the approaches I'm thinking of would work, it might either
suggest a rather painful (and non-obvious) change to the Dbi API, or
it might be possible to define a functor or simple wrapper to turn a
Dbi module into a Dbi' module that works well for this.

And maybe someone who's done a lot of work with classes and modules
will mention a really nifty solution.  :)

John.

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 16:23         ` John Prevost
@ 2004-08-03 16:42           ` Richard Jones
  0 siblings, 0 replies; 13+ messages in thread
From: Richard Jones @ 2004-08-03 16:42 UTC (permalink / raw)
  To: John Prevost; +Cc: Ocaml Mailing List

On Tue, Aug 03, 2004 at 12:23:07PM -0400, John Prevost wrote:
> Yes, that's the same problem I'm seeing.  I think it *might* be
> possible to get around it by using a connection type with type
> parameters.  Maybe.  I'll investigate more in a few hours.
> 
> This is an upsetting problem, but I believe that it's known that there
> are some drawbacks to mixing classes and functors.  (And, well, if
> it's not, it should be now.)  Anyway, we'll see what can be done.
> 
> If one of the approaches I'm thinking of would work, it might either
> suggest a rather painful (and non-obvious) change to the Dbi API, or
> it might be possible to define a functor or simple wrapper to turn a
> Dbi module into a Dbi' module that works well for this.
> 
> And maybe someone who's done a lot of work with classes and modules
> will mention a really nifty solution.  :)

One "solution" I've come up with is to add a functional interface to
Dbi_postgres.  ie: adding this to the end:

  let connect ?host ?port ?user ?password database =
    new connection ?host ?port ?user ?password database
  let close (dbh : connection) = dbh#close ()
  let closed (dbh : connection) = dbh#closed
  let commit (dbh : connection) = dbh#commit ()
  let ping (dbh : connection) = dbh#ping ()
  let rollback (dbh : connection) = dbh#rollback ()

then I've changed the functor input signature to:

  module type DbiDriverT = sig
    type connection
    val connect : ?host:string -> ?port:string ->
      ?user:string -> ?password:string -> string ->
      connection
    val close : connection -> unit
    val closed : connection -> bool
    val commit : connection -> unit
    val ping : connection -> bool
    val rollback : connection -> unit
  end

with appropriate changes to the functor itself to use the functions
instead of methods.

It works, but it's not particularly elegant, and a better solution
would be welcome.

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
'There is a joke about American engineers and French engineers. The
American team brings a prototype to the French team. The French team's
response is: "Well, it works fine in practice; but how will it hold up
in theory?"'

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 15:28           ` John Prevost
@ 2004-08-03 19:57             ` brogoff
  2004-08-03 22:05               ` brogoff
  0 siblings, 1 reply; 13+ messages in thread
From: brogoff @ 2004-08-03 19:57 UTC (permalink / raw)
  To: Ocaml Mailing List

On Tue, 3 Aug 2004, John Prevost wrote:
> Oops.  A couple of errors in that last thing I wrote that weren't the
> problem I was trying to illustrate (that's what I get for trying fixes
> inline before giving up):
>
> module type ThingPoolT =
>   sig
>     type connection
>     val connect : unit -> connection
>     val test : connection -> int
>   end
>
> module ThingPool (Thing : ThingIntf) :
>     (ThingPoolT with type connection = Thing.connection) =
>   struct
>     type connection = Thing.connection
>     let connect () = Thing.connect ()
>     let test x = x#a + 1
>   end

Certainly if you're going to call method a it needs to be exposed. If I
understand the problems you're trying to demonstrate, the following would be
my stab at it. Untested code, caveat emptor, blah blah blah...

module type ThingIntf =
  sig
    type 'a connection =
        'a constraint 'a = < a: int; connect : unit -> 'a connection; ..>
    val connect : unit -> 'a connection
  end;;

module type ThingPoolT =
  sig
    include ThingIntf
    val test : 'a connection -> int
  end;;

module ThingPool (Thing : ThingIntf) : ThingPoolT =
  struct
    include Thing

    let connect () =
      let conn = Thing.connect () in
      ignore (conn#a);
      conn

    let (test : _ connection -> int) = fun x -> x#a + 1
  end;;

-- Brian

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 19:57             ` brogoff
@ 2004-08-03 22:05               ` brogoff
  2004-08-03 23:24                 ` John Prevost
  0 siblings, 1 reply; 13+ messages in thread
From: brogoff @ 2004-08-03 22:05 UTC (permalink / raw)
  To: Ocaml Mailing List

Ha, I just tried whipping up an example and I couldn't write a Thing.

Oh well, classes/polymorphic variants and the type abstraction features of
functors are hard to use together!

On Tue, 3 Aug 2004, brogoff wrote:

> On Tue, 3 Aug 2004, John Prevost wrote:
> > Oops.  A couple of errors in that last thing I wrote that weren't the
> > problem I was trying to illustrate (that's what I get for trying fixes
> > inline before giving up):
> >
> > module type ThingPoolT =
> >   sig
> >     type connection
> >     val connect : unit -> connection
> >     val test : connection -> int
> >   end
> >
> > module ThingPool (Thing : ThingIntf) :
> >     (ThingPoolT with type connection = Thing.connection) =
> >   struct
> >     type connection = Thing.connection
> >     let connect () = Thing.connect ()
> >     let test x = x#a + 1
> >   end
>
> Certainly if you're going to call method a it needs to be exposed. If I
> understand the problems you're trying to demonstrate, the following would be
> my stab at it. Untested code, caveat emptor, blah blah blah...
>
> module type ThingIntf =
>   sig
>     type 'a connection =
>         'a constraint 'a = < a: int; connect : unit -> 'a connection; ..>
>     val connect : unit -> 'a connection
>   end;;
>
> module type ThingPoolT =
>   sig
>     include ThingIntf
>     val test : 'a connection -> int
>   end;;
>
> module ThingPool (Thing : ThingIntf) : ThingPoolT =
>   struct
>     include Thing
>
>     let connect () =
>       let conn = Thing.connect () in
>       ignore (conn#a);
>       conn
>
>     let (test : _ connection -> int) = fun x -> x#a + 1
>   end;;
>
> -- Brian
>
> -------------------
> 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
>

-------------------
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


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [Caml-list] Functors and classes
  2004-08-03 22:05               ` brogoff
@ 2004-08-03 23:24                 ` John Prevost
  0 siblings, 0 replies; 13+ messages in thread
From: John Prevost @ 2004-08-03 23:24 UTC (permalink / raw)
  To: Ocaml Mailing List

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


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2004-08-03 23:24 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-08-03 12:02 [Caml-list] Functors and classes Richard Jones
2004-08-03 12:10 ` Richard Jones
2004-08-03 13:17   ` Richard Jones
2004-08-03 15:06     ` John Prevost
2004-08-03 15:12       ` Richard Jones
2004-08-03 15:27         ` John Prevost
2004-08-03 15:28           ` John Prevost
2004-08-03 19:57             ` brogoff
2004-08-03 22:05               ` brogoff
2004-08-03 23:24                 ` John Prevost
2004-08-03 15:50       ` Richard Jones
2004-08-03 16:23         ` John Prevost
2004-08-03 16:42           ` Richard Jones

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).