From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by walapai.inria.fr (8.13.6/8.13.6) with ESMTP id p1I6jC25012317 for ; Fri, 18 Feb 2011 07:45:12 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AqsGALOkXU2FBoIF/2dsb2JhbACYFo59rkeNWgEEhV6FDIcI X-IronPort-AV: E=Sophos;i="4.62,185,1297033200"; d="scan'208";a="76150958" Received: from rabbit.math.nagoya-u.ac.jp (HELO mailhost.math.nagoya-u.ac.jp) ([133.6.130.5]) by mail3-smtp-sop.national.inria.fr with ESMTP; 18 Feb 2011 07:45:06 +0100 Received: from mailhost.math.nagoya-u.ac.jp (localhost [127.0.0.1]) by mailhost.math.nagoya-u.ac.jp (Postfix) with ESMTP id 41C07372 for ; Fri, 18 Feb 2011 15:45:03 +0900 (JST) Received: from mailhost.math.nagoya-u.ac.jp (camel-172 [172.16.254.4]) by mailhost.math.nagoya-u.ac.jp (Postfix) with ESMTP id E096B430 for ; Fri, 18 Feb 2011 15:45:02 +0900 (JST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=math.nagoya-u.ac.jp; h= date:message-id:to:subject:from:mime-version:content-type: content-transfer-encoding; s=alpha; bh=e5y6oHG1Dt7gwJLft8ybfPFRx 00=; b=eEP4SxJiX8opXb39djhWqZxhIqLyfndOTTifaiJ+CM203ma4hmxiJAppT Q9HAursr83i13vh2uqwXglPU2+BoPT+i8Z5brh8UKJ735ediOo+q2+dRHsqVE+AK G8yMEknk/R7zebH2wCgCKkQNu76060WJoBKjE+7PcqxDTTEkQ4= DomainKey-Signature: a=rsa-sha1; h=Received:Date:Message-Id:To:Subject:From:X-Mailer:Mime-Version:Content-Type:Content-Transfer-Encoding; b=jEt1i7tsRxWbqQ8mkArfekdXMqtynBi51zTVoZPz9BI+k1G94FJQvVQ45BPGdDh3ZgZuMSwPmMWnwRq71KVBWGx5GeIJthp7v6/dXp5VTV/ECWVaPuXB00jMkotHX8/i56TGbP5VOiBYd/81MpkweyddpgzMFctqcleZrtSb3K0=; c=nofws; d=math.nagoya-u.ac.jp; q=dns; s=alpha Received: from localhost (bsdserver02 [172.16.249.2]) by mailhost.math.nagoya-u.ac.jp (Postfix) with ESMTP id 8F8E4372 for ; Fri, 18 Feb 2011 15:45:02 +0900 (JST) Date: Fri, 18 Feb 2011 15:44:43 +0900 (JST) Message-Id: <20110218.154443.07636736.garrigue@math.nagoya-u.ac.jp> To: caml-list@inria.fr From: Jacques Garrigue X-Mailer: Mew version 6.3 on Emacs 22.3 / Mule 5.0 (SAKAKI) Mime-Version: 1.0 Content-Type: Text/Plain; charset=us-ascii Content-Transfer-Encoding: 7bit Subject: [Caml-list] Encoding objects using recursive first-class modules Dear Camlers, There has been some excitement about the possibilities of first-class modules. One application is to use them as objects, as is already done in the amthing project (using interesting syntactic sugar). This may interest some people that the relation to objects doesn't stop at the concrete object level: combining them with recursive modules, one can also easily encode classes, with virtual methods and inheritance. The basic idea is to turn classes (or rather "traits") into functors from the final object to a list of methods. Here is a bit of code demonstrating this. This code is rather verbose, but using 3.13 features and amthing syntax it can be made much lighter. Jacques Garrigue (* Signature for points, all methods must be functions *) module type Point = sig val get_x : unit -> int val move : int -> unit end (* The Point class, with state x *) (* Needs to be a functor, to allow creating new state *) module PointF(X : sig end) = struct let x = ref 0 let get_x () = !x let move d = x := !x + d end (* Create a new point *) let new_point () = (module PointF(struct end) : Point) (* Signature for the Show trait *) module type Show = sig val show : unit -> string end (* Implementation for the Show trait *) module ShowF(P : Point) = struct let show () = Printf.sprintf "x = %i" (P.get_x ()) end (* Signature for the ShowPoint class *) module type ShowPoint = sig include Point include Show end (* ShowPoint class *) module ShowPointF(P : ShowPoint) = struct include PointF(P) include ShowF(P) end (* Create a new ShowPoint object, by tying the knot *) let new_showpoint () = let module M = struct module rec SP : ShowPoint = ShowPointF(SP) end in (module M.SP : ShowPoint) (* Play with it *) let sp = new_showpoint () let a = let module SP = (val sp : ShowPoint) in SP.move 2; SP.show () (* One can coerce to a supertype *) let sp_as_p = (module (val sp : ShowPoint) : Point)