Version française
Home     About     Download     Resources     Contact us    
Browse thread
OCaml object types vs record types
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Pierre-Evariste Dagand <pedagand@g...>
Subject: Re: [Caml-list] OCaml object types vs record types
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 <rajb@rice.edu>:
> 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 = <name : string>
> type specialobj = <name: string; mutable value: int;...>
>
> 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