From: "Pierre-Evariste Dagand" <pedagand@gmail.com>
To: caml-list@yquem.inria.fr
Subject: Re: [Caml-list] OCaml object types vs record types
Date: Mon, 4 Jun 2007 21:55:16 +0200 [thread overview]
Message-ID: <6cb897b30706041255v4f9b4cb7w1a571d67bf52752e@mail.gmail.com> (raw)
In-Reply-To: <0EE1C559-A93C-4E66-AC70-8ADD1C21DDF8@rice.edu>
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
next prev parent reply other threads:[~2007-06-04 19:55 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-06-04 16:45 Raj B
2007-06-04 19:55 ` Pierre-Evariste Dagand [this message]
2007-06-04 20:13 ` [Caml-list] " Nicolas Pouillard
2007-06-04 22:06 ` Lukasz Stafiniak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=6cb897b30706041255v4f9b4cb7w1a571d67bf52752e@mail.gmail.com \
--to=pedagand@gmail.com \
--cc=caml-list@yquem.inria.fr \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox