From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.0 required=5.0 tests=AWL,SPF_NEUTRAL autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from discorde.inria.fr (discorde.inria.fr [192.93.2.38]) by yquem.inria.fr (Postfix) with ESMTP id 2F245BC0A for ; Mon, 4 Jun 2007 21:55:18 +0200 (CEST) Received: from an-out-0708.google.com (an-out-0708.google.com [209.85.132.249]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id l54JtHKW021728 for ; Mon, 4 Jun 2007 21:55:17 +0200 Received: by an-out-0708.google.com with SMTP id b15so422625ana for ; Mon, 04 Jun 2007 12:55:16 -0700 (PDT) DKIM-Signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=Yoi6IUenv2D4GZrKciI5BS5N/S+lZ1FhLzsunaM/+5AN803MzghFKSeBo+ljlZ2R18ISDWkgM2fP2EyqCLzTXRcCTumKyp/4KG0Fr3IIs4FyWhk/+Axq9x0PuaatB5epFhOpI+J7D0LThpHwEg77D8eTG7LtJvrFIGAatm4hz48= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=QfojxXQGf49w1ubuQxwOQ3N4rWo9XbPkH9oQllcLPMoDa+yRXdqaCne6B7jLvc6aw5+WoY7DJbJSB/1m6mu+1DpqlLIr7ta6zWRs41EgbDIuP9RKsnf4JJTPyUuNEJAgCveG2DrUca7gJK/FsZTyIKJJxcflr39NyPfk5CH1ACU= Received: by 10.100.112.19 with SMTP id k19mr2775635anc.1180986916654; Mon, 04 Jun 2007 12:55:16 -0700 (PDT) Received: by 10.100.121.17 with HTTP; Mon, 4 Jun 2007 12:55:16 -0700 (PDT) Message-ID: <6cb897b30706041255v4f9b4cb7w1a571d67bf52752e@mail.gmail.com> Date: Mon, 4 Jun 2007 21:55:16 +0200 From: "Pierre-Evariste Dagand" To: caml-list@yquem.inria.fr Subject: Re: [Caml-list] OCaml object types vs record types In-Reply-To: <0EE1C559-A93C-4E66-AC70-8ADD1C21DDF8@rice.edu> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <0EE1C559-A93C-4E66-AC70-8ADD1C21DDF8@rice.edu> X-j-chkmail-Score: MSGID : 46646E25.000 on discorde : j-chkmail score : XXX : 5/20 1 0.000 -> 3 X-Miltered: at discorde with ID 46646E25.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; ocaml:01 functors:01 sig:01 val:01 val:01 struct:01 struct:01 mutable:01 sig:01 functor:01 mutable:01 functors:01 usefull:01 subtyping:01 ocaml:01 You might be able to modelize objects with record through functors. Let's give a try. Firstly, encapsulate the record and its methods in a module Obj : module type OBJ = sig type obj val new_obj : string -> obj val get_name : obj -> string end ;; module FObj = struct type obj = { name : string } let new_obj s = { name = s } let get_name obj = obj.name end ;; module Obj = (FObj : OBJ) ;; There we have a basic object, additional methods operating on Obj.obj, especially to_string, could be useful and implemented in the module. Now, define the special object over Obj : module FSpecialObjInt (Obj : OBJ) = struct type obj = { mutable value : int ; extends : Obj.obj } let new_obj name value = { value = value ; extends = Obj.new_obj name } let get_name obj = Obj.get_name obj.extends let get_value obj = obj.value let set_value obj v = obj.value <- v end module type SPECIAL_OBJ_INT = sig type obj val new_obj : string -> int -> obj val get_name : obj -> string val get_value : obj -> int val set_value : obj -> int -> unit end module SpecialObjInt = FSpecialObjInt(Obj) Thus we have extended Obj by adding a value record plus its getter/setter. Again, methods on SpecialObjInt could be put in the functor. We could also build a special object on Float : module FSpecialObjFloat (Obj : OBJ) = struct type obj = { mutable value : float ; extends : Obj.obj } let new_obj name value = { value = value ; extends = Obj.new_obj name } let get_name obj = Obj.get_name obj.extends let get_value obj = obj.value let set_value obj v = obj.value <- v end module type SPECIAL_OBJ_FLOAT = sig type obj val new_obj : string -> float -> obj val get_name : obj -> string val get_value : obj -> float val set_value : obj -> float -> unit end module SpecialObjFloat = FSpecialObjFloat(Obj) Again, we have extended Obj. But the most interesting might be to build a super object of SpecialObjInt and SpecialObjFloat : module FSuperObj (ObjInt : SPECIAL_OBJ_INT) (ObjFloat : SPECIAL_OBJ_FLOAT) = struct type obj = { name : string ; extends_int : ObjInt.obj ; extends_float : ObjFloat.obj } let new_obj super_name int_name int_value float_name float_value = { name = super_name ; extends_int = ObjInt.new_obj int_name int_value ; extends_float = ObjFloat.new_obj float_name float_value } let get_int_name obj = ObjInt.get_name obj.extends_int let get_int_value obj = ObjInt.get_value obj.extends_int let set_int_value obj v = ObjInt.set_value obj.extends_int v let get_float_name obj = ObjFloat.get_name obj.extends_float let get_float_value obj = ObjFloat.get_value obj.extends_float let set_float_value obj v = ObjFloat.set_value obj.extends_float v let get_name obj = obj.name let to_string obj = let name = get_name obj and int_name = get_int_name obj and int_value = get_int_value obj and float_name = get_float_name obj and float_value = get_float_value obj in "Name : " ^ name ^ "\n\t" ^ "Int name : " ^ int_name ^ "\n\t" ^ "Int value : " ^ (string_of_int int_value) ^ "\n\t" ^ "Float name : " ^ float_name ^ "\n\t" ^ "Float value : " ^ (string_of_float float_value) ^ "\n" end module type SUPER_OBJ = sig type obj val new_obj : string -> string -> int -> string -> float -> obj val get_int_name : obj -> string val get_int_value : obj -> int val set_int_value : obj -> int -> unit val get_float_name : obj -> string val get_float_value : obj -> float val set_float_value : obj -> float -> unit val get_name : obj -> string val to_string : obj -> string end module SuperObj = FSuperObj(SpecialObjInt)(SpecialObjFloat) Let's use it : (* Basic obj *) let obj = Obj.new_obj "test";; Obj.get_name obj;; (* First special obj *) let special_obj1 = SpecialObjInt.new_obj "test" 2 ;; let name = SpecialObjInt.get_name special_obj1 and value = SpecialObjInt.get_value special_obj1;; SpecialObjInt.set_value special_obj1 3;; let value = SpecialObjInt.get_value special_obj1;; (* The same for the second special obj *) (* Super obj *) let super_obj = SuperObj.new_obj "Super Obj" "Int obj" 2 "Float obj" 4.2 ;; let name = SuperObj.get_name super_obj and int_name = SuperObj.get_int_name super_obj and int_value = SuperObj.get_int_value super_obj and float_name = SuperObj.get_float_name super_obj and float_value = SuperObj.get_float_value super_obj ;; print_string (SuperObj.to_string super_obj);; SuperObj.set_int_value super_obj 1;; SuperObj.set_float_value super_obj 1.2;; print_string (SuperObj.to_string super_obj);; The main point with using functors is performance : while using functors in a project of mine, I have noticed about 12% performance lost compared to a raw implementation. Besides, in the present code, there could be a deep cascade of function calls so you might not achieve good performance. To my mind, defunctorisation would be really usefull in that case. 2007/6/4, Raj B : > Hi there > > I'm writing an application where I'd modeling objects as record > types. However, I'd like to have a subtyping relation between them > along with (occasional) coercion. For example, > > type obj = {name : string} > type specialobj = {name: string; mutable value: int;...} > and so on... > > Obviously, records obviously don't allow me to do this. In fact, I > can't even define two record types with the same field 'name'. I have > to define the 'largest' possible type i.e. specialobj and just leave > fields undefined (default value) when I don't need them. This is > fine, except that it eats up tons of memory because my records are > quite large and slows things down. On profiling, I find that most of > my time goes in the OCaml function 'caml_dup', which, I believe, > copies structures. I am very concerned about speed in my application. > > I'm not sure I need the entire machinery of classes (since, I > understand that it can be pretty slow too?) and all that goes with > it, so I was wondering if using object types might serve the purpose. > > type obj = > type specialobj = > > Unfortunately, it doesn't seem possible to define 'mutable' fields in > the same way as records. I'd have to define methods to get and set > values, so it seems like there's very little difference from class > definitions. Please correct me if I'm wrong. > > Is there any way to get what I want (records with subtyping/coercion > behavior) without using classes? In case I do end up using classes, > what kind of performance penalty am I looking at? > > Thanks! > Raj > > _______________________________________________ > Caml-list mailing list. Subscription management: > http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list > Archives: http://caml.inria.fr > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > -- Pierre-Evariste DAGAND http://perso.eleves.bretagne.ens-cachan.fr/~dagand/ Empreinte GPG [pgp.mit.edu] : F8CC 61DD 40B7 933F 17CA 061F 5591 AAE6 D3EC 7357