* Execution time of class versus record @ 2007-06-24 15:14 tmp123 2007-06-24 15:29 ` [Caml-list] " Jon Harrop 2007-06-26 13:35 ` Sam Steingold 0 siblings, 2 replies; 20+ messages in thread From: tmp123 @ 2007-06-24 15:14 UTC (permalink / raw) To: caml-list Hello, I've tried to implement two equivalent small programs, the one using class, the other one using records. The resulting execution times says that class are 7-8 times slower than record (compiled with ocamlopt in a Intel machine). Please, knows someone what I'm doing wrong? The programs are: records1.ml ========= type ra = { mutable t : int } let main () = let a = { t = 0 } in for i = 0 to 100000 do a.t <- a.t + i done; Printf.printf "t = %d\n" a.t let _ = let t0 = Unix.gettimeofday () in main(); Printf.printf "elapsed = %f\n" (Unix.gettimeofday() -. t0) class1.ml ======= class ca = object val mutable t = 0 method add x = t <- t+x method get () = t end let main () = let a = new ca in for i = 0 to 100000 do a#add i done; Printf.printf "t = %d\n" (a#get()) let _ = let t0 = Unix.gettimeofday () in main(); Printf.printf "elapsed = %f\n" (Unix.gettimeofday() -. t0) Thanks a lot. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 15:14 Execution time of class versus record tmp123 @ 2007-06-24 15:29 ` Jon Harrop 2007-06-24 15:48 ` Till Varoquaux 2007-06-26 13:35 ` Sam Steingold 1 sibling, 1 reply; 20+ messages in thread From: Jon Harrop @ 2007-06-24 15:29 UTC (permalink / raw) To: caml-list On Sunday 24 June 2007 16:14:54 tmp123@menta.net wrote: > Hello, > > I've tried to implement two equivalent small programs, the one using > class, the other one using records. The resulting execution times says > that class are 7-8 times slower than record (compiled with ocamlopt in a > Intel machine). > > Please, knows someone what I'm doing wrong? You aren't doing anything wrong. -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. The OCaml Journal http://www.ffconsultancy.com/products/ocaml_journal/?e ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 15:29 ` [Caml-list] " Jon Harrop @ 2007-06-24 15:48 ` Till Varoquaux 2007-06-24 16:06 ` Arnaud Spiwack 0 siblings, 1 reply; 20+ messages in thread From: Till Varoquaux @ 2007-06-24 15:48 UTC (permalink / raw) To: caml-list Objects in OCaml are dictionary based, which means methods names must be looked up in a table in order to get there addresses. Record fields on the other hand are addressed directly. Take two files test.ml and test2.ml: test.ml: type b= { field:int } let a={field=1};; print_int a.field test2.ml let a=object method field=1 end;; print_int a#field and dump there intermediate representation (-dlambda) test.ml (setglobal Test! (let (a/61 [0: 1]) (seq (apply (field 27 (global Pervasives!)) (field 0 a/61)) (makeblock 0 a/61)))) test2.ml (setglobal Test2! (let (a/58 (let (class/72 (apply (field 15 (global CamlinternalOO!)) [0: #"field"]) obj_init/80 (let (field/61 (apply (field 6 (global CamlinternalOO!)) class/72 #"field")) (seq (apply (field 10 (global CamlinternalOO!)) class/72 (makeblock 0 field/61 0a 1)) (function env/74 (apply (field 23 (global CamlinternalOO!)) 0a class/72))))) (seq (apply (field 16 (global CamlinternalOO!)) class/72) (apply obj_init/80 0a)))) (seq (apply (field 27 (global Pervasives!)) (send a/58 9671866)) (makeblock 0 a/58)))) You can now understand where the performance issues comes from. Cheers, Till On 6/24/07, Jon Harrop <jon@ffconsultancy.com> wrote: > On Sunday 24 June 2007 16:14:54 tmp123@menta.net wrote: > > Hello, > > > > I've tried to implement two equivalent small programs, the one using > > class, the other one using records. The resulting execution times says > > that class are 7-8 times slower than record (compiled with ocamlopt in a > > Intel machine). > > > > Please, knows someone what I'm doing wrong? > > You aren't doing anything wrong. > > -- > Dr Jon D Harrop, Flying Frog Consultancy Ltd. > The OCaml Journal > http://www.ffconsultancy.com/products/ocaml_journal/?e > > _______________________________________________ > 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 > -- http://till-varoquaux.blogspot.com/ ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 15:48 ` Till Varoquaux @ 2007-06-24 16:06 ` Arnaud Spiwack 2007-06-24 18:18 ` skaller 2007-06-24 18:29 ` Gerd Stolpmann 0 siblings, 2 replies; 20+ messages in thread From: Arnaud Spiwack @ 2007-06-24 16:06 UTC (permalink / raw) To: caml-list Which obviously raises the question: What is the motivation for the object to be encoded differently than records? I remember reading in Xavier Leroy's technical report about the first ZAM how he prepared the field for extensible records (to be able to implement objects). There the name of the fields were compiled into an adress, resulting no runtime conversion. I can imagine a couple of applications to the current situation (though I'm not so sure they would work), but I'm really interested in the original reason of this design choice. Arnaud Spiwack Till Varoquaux a écrit : > Objects in OCaml are dictionary based, which means methods names must > be looked up in a table in order to get there addresses. Record fields > on the other hand are addressed directly. Take two files test.ml and > test2.ml: > test.ml: > type b= > { > field:int > } > let a={field=1};; > print_int a.field > > test2.ml > let a=object > method field=1 > end;; > print_int a#field > > and dump there intermediate representation (-dlambda) > > test.ml > > (setglobal Test! > (let (a/61 [0: 1]) > (seq (apply (field 27 (global Pervasives!)) (field 0 a/61)) > (makeblock 0 a/61)))) > > test2.ml > > (setglobal Test2! > (let > (a/58 > (let > (class/72 (apply (field 15 (global CamlinternalOO!)) [0: > #"field"]) > obj_init/80 > (let > (field/61 > (apply (field 6 (global CamlinternalOO!)) class/72 > #"field")) > (seq > (apply (field 10 (global CamlinternalOO!)) class/72 > (makeblock 0 field/61 0a 1)) > (function env/74 > (apply (field 23 (global CamlinternalOO!)) 0a > class/72))))) > (seq (apply (field 16 (global CamlinternalOO!)) class/72) > (apply obj_init/80 0a)))) > (seq (apply (field 27 (global Pervasives!)) (send a/58 9671866)) > (makeblock 0 a/58)))) > > You can now understand where the performance issues comes from. > > Cheers, > Till > On 6/24/07, Jon Harrop <jon@ffconsultancy.com> wrote: >> On Sunday 24 June 2007 16:14:54 tmp123@menta.net wrote: >> > Hello, >> > >> > I've tried to implement two equivalent small programs, the one using >> > class, the other one using records. The resulting execution times says >> > that class are 7-8 times slower than record (compiled with ocamlopt >> in a >> > Intel machine). >> > >> > Please, knows someone what I'm doing wrong? >> >> You aren't doing anything wrong. >> >> -- >> Dr Jon D Harrop, Flying Frog Consultancy Ltd. >> The OCaml Journal >> http://www.ffconsultancy.com/products/ocaml_journal/?e >> >> _______________________________________________ >> 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 >> > > ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 16:06 ` Arnaud Spiwack @ 2007-06-24 18:18 ` skaller 2007-06-24 18:29 ` Gerd Stolpmann 1 sibling, 0 replies; 20+ messages in thread From: skaller @ 2007-06-24 18:18 UTC (permalink / raw) To: Arnaud Spiwack; +Cc: caml-list On Sun, 2007-06-24 at 18:06 +0200, Arnaud Spiwack wrote: > Which obviously raises the question: What is the motivation for the > object to be encoded differently than records? Someone with more expertise will assuredly correct me, but this is my picture: Ocaml objects can be accessed via a class type. An object matches a type if it has the required methods, matched by name and type (structural typing). For a given class type, objects of different types might match, so there has to be a lookup table mapping the method of the call to the method of the object. Therefore, the indirection is unavoidable. But why can't we use an array, indexed by the method number? This would be possible. However consider a coercion from a class type to a supertype: the supertype might have less methods, or methods in a different order. So the coercion would require dynamically building a new method array. On the other hand with a dictionary, the method lookup is slower, but the same dictionary can be used for the supertype, since statically, you can only lookup a method that is sure to be in the subtype .. the other methods of the subtype simply won't be found. The dictionary of an object is known statically at construction time so it can be created once on program initialisation. This means: construction and coercion are fast, the dictionary is already built. Lookup is slower than optimal. And finally, the dictionary method is easier for the compiler writers: just store the dictionary in the object. -- John Skaller <skaller at users dot sf dot net> Felix, successor to C++: http://felix.sf.net ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 16:06 ` Arnaud Spiwack 2007-06-24 18:18 ` skaller @ 2007-06-24 18:29 ` Gerd Stolpmann 2007-06-24 18:51 ` Arnaud Spiwack 1 sibling, 1 reply; 20+ messages in thread From: Gerd Stolpmann @ 2007-06-24 18:29 UTC (permalink / raw) To: Arnaud Spiwack; +Cc: caml-list Am Sonntag, den 24.06.2007, 18:06 +0200 schrieb Arnaud Spiwack: > Which obviously raises the question: What is the motivation for the > object to be encoded differently than records? Objects support subtyping whereas records do not. And coercion costs nothing, thanks to the object representation. E.g. let print_m2 obj = print_string obj#m2 let x1 = object method m2 = "x1" method m3 = 42 end let x2 = object method m1 = 98 method m2 = "x2" end print_m2 x1 print_m2 x2 See that in x1 the called method m2 is the first in the list, and in x2 it is the second? In a record the order of the components in the memory layout is the same as the order in the type. If we did that the same with objects, we would have to do rearrangements when we coerce objects to supertypes (which happens here when print_m2 is called). Note also that object types are structural and not nominal as for many object-oriented languages (i.e. you don't have to declare that x1 and x2 will be used as subtypes of <m2:string>). > I remember reading in > Xavier Leroy's technical report about the first ZAM how he prepared the > field for extensible records (to be able to implement objects). There > the name of the fields were compiled into an adress, resulting no > runtime conversion. > > I can imagine a couple of applications to the current situation (though > I'm not so sure they would work), but I'm really interested in the > original reason of this design choice. > > > Arnaud Spiwack > > > > Till Varoquaux a écrit : > > Objects in OCaml are dictionary based, which means methods names must > > be looked up in a table in order to get there addresses. Record fields > > on the other hand are addressed directly. Take two files test.ml and > > test2.ml: > > test.ml: > > type b= > > { > > field:int > > } > > let a={field=1};; > > print_int a.field > > > > test2.ml > > let a=object > > method field=1 > > end;; > > print_int a#field > > > > and dump there intermediate representation (-dlambda) > > > > test.ml > > > > (setglobal Test! > > (let (a/61 [0: 1]) > > (seq (apply (field 27 (global Pervasives!)) (field 0 a/61)) > > (makeblock 0 a/61)))) > > > > test2.ml > > > > (setglobal Test2! > > (let > > (a/58 > > (let > > (class/72 (apply (field 15 (global CamlinternalOO!)) [0: > > #"field"]) > > obj_init/80 > > (let > > (field/61 > > (apply (field 6 (global CamlinternalOO!)) class/72 > > #"field")) > > (seq > > (apply (field 10 (global CamlinternalOO!)) class/72 > > (makeblock 0 field/61 0a 1)) > > (function env/74 > > (apply (field 23 (global CamlinternalOO!)) 0a > > class/72))))) > > (seq (apply (field 16 (global CamlinternalOO!)) class/72) > > (apply obj_init/80 0a)))) > > (seq (apply (field 27 (global Pervasives!)) (send a/58 9671866)) > > (makeblock 0 a/58)))) > > > > You can now understand where the performance issues comes from. > > > > Cheers, > > Till > > On 6/24/07, Jon Harrop <jon@ffconsultancy.com> wrote: > >> On Sunday 24 June 2007 16:14:54 tmp123@menta.net wrote: > >> > Hello, > >> > > >> > I've tried to implement two equivalent small programs, the one using > >> > class, the other one using records. The resulting execution times says > >> > that class are 7-8 times slower than record (compiled with ocamlopt > >> in a > >> > Intel machine). > >> > > >> > Please, knows someone what I'm doing wrong? > >> > >> You aren't doing anything wrong. > >> > >> -- > >> Dr Jon D Harrop, Flying Frog Consultancy Ltd. > >> The OCaml Journal > >> http://www.ffconsultancy.com/products/ocaml_journal/?e > >> > >> _______________________________________________ > >> 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 > >> > > > > > > _______________________________________________ > 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 > -- ------------------------------------------------------------ Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany gerd@gerd-stolpmann.de http://www.gerd-stolpmann.de Phone: +49-6151-153855 Fax: +49-6151-997714 ------------------------------------------------------------ ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 18:29 ` Gerd Stolpmann @ 2007-06-24 18:51 ` Arnaud Spiwack 2007-06-24 19:11 ` Chris King 2007-06-25 3:25 ` Jon Harrop 0 siblings, 2 replies; 20+ messages in thread From: Arnaud Spiwack @ 2007-06-24 18:51 UTC (permalink / raw) To: caml-list Well, this was quite a misunderstanding of my question. Obviously objects are not records. But the essential difference seems to be more at type level (btw object coercion should never cost anything since they are merely type level tools). At runtime, I can't see anything to preven objects to be exactly records (with a bit of care taken during compilation for method names). John Skaller's answer is not really convincing either, since the type of a value does not change the size of the value, having the same name associated to different types does not seem to me a good motivation. I was referring earlier to Xavier Leroy's technical report, I can't remember precisely what the principle was, but there was some sort of label compilation for records with shared names. I tend to remember that it used a sparse encoding of records (with holes corresponding to the missing labels), thus it might have been a problem, but I believe the representation was rather dense in case of only-unique-name-based record. Another lead is maybe something due to module compilation, the earlier idea might imply that each module has it's own namespace (it's the case for almost everything in OCaml, except, if I'm not mistaking, method names). If it is the motivation for having a runtime representation of objects different to that of records, the question that raises nex is: what is the motivation for not having module-specific namespaces for method names? Arnaud Spiwack Gerd Stolpmann a écrit : > Am Sonntag, den 24.06.2007, 18:06 +0200 schrieb Arnaud Spiwack: > >> Which obviously raises the question: What is the motivation for the >> object to be encoded differently than records? >> > > Objects support subtyping whereas records do not. And coercion costs > nothing, thanks to the object representation. > > E.g. > > let print_m2 obj = print_string obj#m2 > > let x1 = object method m2 = "x1" method m3 = 42 end > > let x2 = object method m1 = 98 method m2 = "x2" end > > print_m2 x1 > print_m2 x2 > > See that in x1 the called method m2 is the first in the list, and in x2 > it is the second? In a record the order of the components in the memory > layout is the same as the order in the type. If we did that the same > with objects, we would have to do rearrangements when we coerce objects > to supertypes (which happens here when print_m2 is called). > > Note also that object types are structural and not nominal as for many > object-oriented languages (i.e. you don't have to declare that x1 and x2 > will be used as subtypes of <m2:string>). > > >> I remember reading in >> Xavier Leroy's technical report about the first ZAM how he prepared the >> field for extensible records (to be able to implement objects). There >> the name of the fields were compiled into an adress, resulting no >> runtime conversion. >> >> I can imagine a couple of applications to the current situation (though >> I'm not so sure they would work), but I'm really interested in the >> original reason of this design choice. >> >> >> Arnaud Spiwack >> >> >> >> Till Varoquaux a écrit : >> >>> Objects in OCaml are dictionary based, which means methods names must >>> be looked up in a table in order to get there addresses. Record fields >>> on the other hand are addressed directly. Take two files test.ml and >>> test2.ml: >>> test.ml: >>> type b= >>> { >>> field:int >>> } >>> let a={field=1};; >>> print_int a.field >>> >>> test2.ml >>> let a=object >>> method field=1 >>> end;; >>> print_int a#field >>> >>> and dump there intermediate representation (-dlambda) >>> >>> test.ml >>> >>> (setglobal Test! >>> (let (a/61 [0: 1]) >>> (seq (apply (field 27 (global Pervasives!)) (field 0 a/61)) >>> (makeblock 0 a/61)))) >>> >>> test2.ml >>> >>> (setglobal Test2! >>> (let >>> (a/58 >>> (let >>> (class/72 (apply (field 15 (global CamlinternalOO!)) [0: >>> #"field"]) >>> obj_init/80 >>> (let >>> (field/61 >>> (apply (field 6 (global CamlinternalOO!)) class/72 >>> #"field")) >>> (seq >>> (apply (field 10 (global CamlinternalOO!)) class/72 >>> (makeblock 0 field/61 0a 1)) >>> (function env/74 >>> (apply (field 23 (global CamlinternalOO!)) 0a >>> class/72))))) >>> (seq (apply (field 16 (global CamlinternalOO!)) class/72) >>> (apply obj_init/80 0a)))) >>> (seq (apply (field 27 (global Pervasives!)) (send a/58 9671866)) >>> (makeblock 0 a/58)))) >>> >>> You can now understand where the performance issues comes from. >>> >>> Cheers, >>> Till >>> On 6/24/07, Jon Harrop <jon@ffconsultancy.com> wrote: >>> >>>> On Sunday 24 June 2007 16:14:54 tmp123@menta.net wrote: >>>> >>>>> Hello, >>>>> >>>>> I've tried to implement two equivalent small programs, the one using >>>>> class, the other one using records. The resulting execution times says >>>>> that class are 7-8 times slower than record (compiled with ocamlopt >>>>> >>>> in a >>>> >>>>> Intel machine). >>>>> >>>>> Please, knows someone what I'm doing wrong? >>>>> >>>> You aren't doing anything wrong. >>>> >>>> -- >>>> Dr Jon D Harrop, Flying Frog Consultancy Ltd. >>>> The OCaml Journal >>>> http://www.ffconsultancy.com/products/ocaml_journal/?e >>>> >>>> _______________________________________________ >>>> 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 >>>> >>>> >>> >> _______________________________________________ >> 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 >> >> ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 18:51 ` Arnaud Spiwack @ 2007-06-24 19:11 ` Chris King 2007-06-25 3:25 ` Jon Harrop 1 sibling, 0 replies; 20+ messages in thread From: Chris King @ 2007-06-24 19:11 UTC (permalink / raw) To: Arnaud Spiwack; +Cc: caml-list On 6/24/07, Arnaud Spiwack <aspiwack@lix.polytechnique.fr> wrote: > Another lead is maybe something due to module compilation, the > earlier idea might imply that each module has it's own namespace (it's > the case for almost everything in OCaml, except, if I'm not mistaking, > method names). And polymorphic variants. If you consider objects as extensible records, ignoring instance variables and initializers and pretending they support pattern matching and the "with" syntax, then their design is essentially the record analogue of polymorphic variants. Hence a global namespace. - Chris ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-24 18:51 ` Arnaud Spiwack 2007-06-24 19:11 ` Chris King @ 2007-06-25 3:25 ` Jon Harrop 2007-06-25 11:16 ` Arnaud Spiwack 1 sibling, 1 reply; 20+ messages in thread From: Jon Harrop @ 2007-06-25 3:25 UTC (permalink / raw) To: caml-list On Sunday 24 June 2007 19:51:02 Arnaud Spiwack wrote: > ...btw object coercion should never cost anything > since they are merely type level tools... Even in statically typed systems you might well want to shift work to run-time (e.g. specialization of all-float records/arrays) so I see no reason to expect coercion to be free. > At runtime, I can't see anything to preven objects to be exactly records > (with a bit of care taken during compilation for method names). How can the current representation of records handle virtual method dispatch? > John > Skaller's answer is not really convincing either, since the type of a > value does not change the size of the value, having the same name > associated to different types does not seem to me a good motivation. I think this choice makes OCaml's object system more orthogonal to the rest of the language. > Another lead is maybe something due to module compilation, the > earlier idea might imply that each module has it's own namespace (it's > the case for almost everything in OCaml, except, if I'm not mistaking, > method names and polymorphic variants. > If it is the motivation for having a runtime > representation of objects different to that of records, the question > that raises nex is: what is the motivation for not having > module-specific namespaces for method names? If I have two modules containing two classes and I want them to be related, how can you implement that with structurally-subtyped OO if method names are local to modules? -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. The OCaml Journal http://www.ffconsultancy.com/products/ocaml_journal/?e ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-25 3:25 ` Jon Harrop @ 2007-06-25 11:16 ` Arnaud Spiwack 2007-06-25 12:07 ` Jon Harrop 0 siblings, 1 reply; 20+ messages in thread From: Arnaud Spiwack @ 2007-06-25 11:16 UTC (permalink / raw) To: caml-list >> ...btw object coercion should never cost anything >> since they are merely type level tools... >> > > Even in statically typed systems you might well want to shift work to run-time > (e.g. specialization of all-float records/arrays) so I see no reason to > expect coercion to be free. > Well even in dynamically typed languages, a coercion should at runtime cost no more than a soundness check which is part of virtually any operation. But well, I guess you mean that coercion could lead to a kind of object which is optimized in a certain way. Which I hadn't actually thought of, but this should be taken care of at compile time (if I remember well, the arrays of floats are actually compiled a different way, using different get/set primitive, there is still nothing at runtime). So in vew of this, the part of the coercion that'd be shift at run-time would be something rather rare (in the zoology of objects, object that deserve a specific run-time representation sound like a rather spare subset to me), an coincidental. Most coercion would still be no-ops. Am I wrong ? > >> At runtime, I can't see anything to preven objects to be exactly records >> (with a bit of care taken during compilation for method names). >> > > How can the current representation of records handle virtual method dispatch? > I'm not sure I will answer this question properly. But if we're talking of the same thing, virtual methods are not a runtime concern. You can't create object of a virtual class anyway. It's a mere typing issue (and this time for very real, this does not fiddle with any concrete representation of any sort). I guess I haven't understand the question. > >> John >> Skaller's answer is not really convincing either, since the type of a >> value does not change the size of the value, having the same name >> associated to different types does not seem to me a good motivation. >> > > I think this choice makes OCaml's object system more orthogonal to the rest of > the language. > Which specific choice are you refering to right now? (you lost me somewhere on the track). > >> Another lead is maybe something due to module compilation, the >> earlier idea might imply that each module has it's own namespace (it's >> the case for almost everything in OCaml, except, if I'm not mistaking, >> method names >> > > and polymorphic variants. > Indeed. For similar reason I reckon. I wonder how polymorphic variants are handled at compile time. They probably get there label during linking I guess. I can't see how they'd work otherwise. (the OCaml manual states they are a pinch slower than non-polymorphic variants, could someone tell me what is the difference which makes that be?) > >> If it is the motivation for having a runtime >> representation of objects different to that of records, the question >> that raises nex is: what is the motivation for not having >> module-specific namespaces for method names? >> > > If I have two modules containing two classes and I want them to be related, > how can you implement that with structurally-subtyped OO if method names are > local to modules? > Well, you could still use #OtherModule.m to call the other module's "m" method. And using "open OtherModule" as well. I must confess I'm not so sure it really makes a lot of sense to have these like that, but at least it'd be rather consistent. Anyway, since we raised the polymorphic variant point, it sounds unlikely that it'd be impossible to give non-colliding adresses to method names during linking, so this point is rather moot. Arnaud Spiwack ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-25 11:16 ` Arnaud Spiwack @ 2007-06-25 12:07 ` Jon Harrop 2007-06-25 23:59 ` Jonathan Bryant 2007-06-28 1:13 ` Christian Stork 0 siblings, 2 replies; 20+ messages in thread From: Jon Harrop @ 2007-06-25 12:07 UTC (permalink / raw) To: caml-list On Monday 25 June 2007 12:16:08 Arnaud Spiwack wrote: > if I remember well, > the arrays of floats are actually compiled a different way, using > different get/set primitive, Yes. > there is still nothing at runtime Not quite: there is now run-time dispatch to the appropriate get/set primitive in polymorphic functions. > ). So in > vew of this, the part of the coercion that'd be shift at run-time would > be something rather rare (in the zoology of objects, object that deserve > a specific run-time representation sound like a rather spare subset to > me), an coincidental. If these cases were rare, compiler writers would not bother optimizing them. > > How can the current representation of records handle virtual method > > dispatch? > > I'm not sure I will answer this question properly. But if we're talking > of the same thing, virtual methods are not a runtime concern. You can't > create object of a virtual class anyway. It's a mere typing issue (and > this time for very real, this does not fiddle with any concrete > representation of any sort). > > I guess I haven't understand the question. Run-time dispatch of virtual functions is the object oriented representation of sum types, so it can require run-time dispatch. > > I think this choice makes OCaml's object system more orthogonal to the > > rest of the language. > > Which specific choice are you refering to right now? (you lost me > somewhere on the track). Structurally sub-typed OOP complements the Hindley-Milner type system, IMHO. > > and polymorphic variants. > > Indeed. For similar reason I reckon. > I wonder how polymorphic variants are handled at compile time. Like an ordinary variant with a single boxed argument but their ID is a hash of the string name of the constructor instead of an enumeration. > They > probably get there label during linking I guess. I can't see how they'd > work otherwise. (the OCaml manual states they are a pinch slower than > non-polymorphic variants, could someone tell me what is the difference > which makes that be?) Polymorphic variant type constructors may have different numbers of arguments, so their representation is always boxed whereas multiple-argument variant types are unboxed. For the same reason, there is a difference between: type t = A of int * int and: type t = A of (int * int) The former is unboxed and the latter is boxed (a reference to a pair). The boxing can degrade performance (it can also improve performance!). Pattern matching is also less efficient for polymorphic variants. Look at the compiled bytecode, for example: type x = A | B | C let f = function | A -> 0 | B -> 1 | C -> 2 compiles to an efficient O(1) virtual table: L1: acc 0 switch 5 4 3/ L5: const 0 return 1 L4: const 1 return 1 L3: const 2 return 1 but: let g = function | `A -> 0 | `B -> 1 | `C -> 2 compiles to O(n) comparisons: L1: acc 0 push const 66 neqint branchifnot L3 acc 0 push const 67 leint branchifnot L4 const 2 return 1 L4: const 0 return 1 L3: const 1 return 1 > > If I have two modules containing two classes and I want them to be > > related, how can you implement that with structurally-subtyped OO if > > method names are local to modules? > > Well, you could still use #OtherModule.m to call the other module's "m" > method. And using "open OtherModule" as well. I must confess I'm not so > sure it really makes a lot of sense to have these like that, but at > least it'd be rather consistent. I was referring to virtual function dispatch and not the explicit invocation of a particular member. Consider this example: module A = struct let foo = object method f n = n+1 end end;; module B = struct let bar = object method f n = n+2 end end;; let apply o = o#f;; apply A.foo 0;; apply B.bar 0;; If modules imposed separate namespaces then the objects in the modules A and B could not be related, so you could not use them for dispatch in this way (probably a very common use of objects as well). -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. The OCaml Journal http://www.ffconsultancy.com/products/ocaml_journal/?e ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-25 12:07 ` Jon Harrop @ 2007-06-25 23:59 ` Jonathan Bryant 2007-06-26 0:15 ` Chris King 2007-06-28 1:13 ` Christian Stork 1 sibling, 1 reply; 20+ messages in thread From: Jonathan Bryant @ 2007-06-25 23:59 UTC (permalink / raw) To: Jon Harrop; +Cc: caml-list On Jun 25, 2007, at 8:07 AM, Jon Harrop wrote: > > For the same reason, there is a difference between: > > type t = A of int * int > > and: > > type t = A of (int * int) > > The former is unboxed and the latter is boxed (a reference to a > pair). The > boxing can degrade performance (it can also improve performance!). I've always been a little curious about this. Is performance the _only_ reason for this distinction? Construction and pattern matching on the two are identical, and AFAIK neither doesn't allow partial application. --Jonathan ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-25 23:59 ` Jonathan Bryant @ 2007-06-26 0:15 ` Chris King 2007-06-26 6:53 ` Loup Vaillant 0 siblings, 1 reply; 20+ messages in thread From: Chris King @ 2007-06-26 0:15 UTC (permalink / raw) To: Jonathan Bryant; +Cc: Jon Harrop, caml-list On 6/25/07, Jonathan Bryant <jtbryant@valdosta.edu> wrote: > I've always been a little curious about this. Is performance the > _only_ reason for this distinction? Construction and pattern > matching on the two are identical, and AFAIK neither doesn't allow > partial application. Using the tupled form, you can pattern-match the tuple as a whole. E.g. # type t = A of (int * int);; # match A (1,2) with A x -> x;; int * int = (1, 2) This isn't allowed with the non-tupled form. Same goes for construction. (This is where the non-tupled form can actually cost you, if you need to pass around its arguments as a tuple somewhere.) - Chris ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-26 0:15 ` Chris King @ 2007-06-26 6:53 ` Loup Vaillant 2007-06-26 7:02 ` Jon Harrop 0 siblings, 1 reply; 20+ messages in thread From: Loup Vaillant @ 2007-06-26 6:53 UTC (permalink / raw) To: caml-list On Jun 25, 2007, at 8:07 AM, Jon Harrop wrote: > For the same reason, there is a difference between: > > type t = A of int * int > > and: > > type t = A of (int * int) Err, I don't get it : I see exactly the same thing (written twice) here. Are you telling that : type t = A of int * int <==> type t = (A of int) * int ? Regards, Loup Vaillant ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-26 6:53 ` Loup Vaillant @ 2007-06-26 7:02 ` Jon Harrop 2007-06-26 17:07 ` Loup Vaillant 0 siblings, 1 reply; 20+ messages in thread From: Jon Harrop @ 2007-06-26 7:02 UTC (permalink / raw) To: caml-list On Tuesday 26 June 2007 07:53:01 Loup Vaillant wrote: > Err, I don't get it : I see exactly the same thing (written twice) here. > > Are you telling that : > type t = A of int * int <==> type t = (A of int) * int Nope: # type t1 = A1 of int * int;; type t1 = A1 of int * int # type t2 = A2 of (int * int);; type t2 = A2 of (int * int) The former type has a contructor with two arguments. The latter type has a contructor with one argument that is a pair. Only in the latter case can you contruct directly from a pair: # let a = 1, 2;; val a : int * int = (1, 2) # A1 a;; The constructor A1 expects 2 argument(s), but is here applied to 1 argument(s) # A2 a;; - : t2 = A2 (1, 2) This distinction does not appear with polymorphic variants because they always adopt the latter representation. Despite the additional boxing, the performance trade-offs are non-trivial. For example, a pair can be extracted directly from the latter representation with no allocation required: # function A2 x -> x;; - : t2 -> int * int = <fun> whereas the former requires the construction of a pair: # function A1 x -> x;; The constructor A1 expects 2 argument(s), but is here applied to 1 argument(s) # function A1(x, y) -> x, y;; - : t1 -> int * int = <fun> -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. The OCaml Journal http://www.ffconsultancy.com/products/ocaml_journal/?e ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-26 7:02 ` Jon Harrop @ 2007-06-26 17:07 ` Loup Vaillant 0 siblings, 0 replies; 20+ messages in thread From: Loup Vaillant @ 2007-06-26 17:07 UTC (permalink / raw) To: caml-list 2007/6/26, Jon Harrop <jon@ffconsultancy.com>: > On Tuesday 26 June 2007 07:53:01 Loup Vaillant wrote: > > Err, I don't get it : I see exactly the same thing (written twice) here. > > > > Are you telling that : > > type t = A of int * int <==> type t = (A of int) * int > > Nope: > > # type t1 = A1 of int * int;; > type t1 = A1 of int * int > # type t2 = A2 of (int * int);; > type t2 = A2 of (int * int) > [...] OK, this time, I got it, thanks. You also made me understand why there have been any discussion about partial application of constructors. Loup ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Execution time of class versus record 2007-06-25 12:07 ` Jon Harrop 2007-06-25 23:59 ` Jonathan Bryant @ 2007-06-28 1:13 ` Christian Stork 1 sibling, 0 replies; 20+ messages in thread From: Christian Stork @ 2007-06-28 1:13 UTC (permalink / raw) To: caml-list On Mon, Jun 25, 2007 at 01:07:16PM +0100, Jon Harrop wrote: ... > I was referring to virtual function dispatch and not the explicit invocation > of a particular member. > > Consider this example: > > module A = struct > let foo = object method f n = n+1 end > end;; > module B = struct > let bar = object method f n = n+2 end > end;; > > let apply o = o#f;; > > apply A.foo 0;; > apply B.bar 0;; > > If modules imposed separate namespaces then the objects in the modules A and B > could not be related, so you could not use them for dispatch in this way > (probably a very common use of objects as well). Actually, treating methods much like types wrt module namespaces is a very sensible idea. Without going into further detail of the syntax, in the above example, module A might declare the method A.f and if module B intends to implement a method with same semantics as A.f it could be written as module B = struct let bar = object method A.f n = n+2 end end;; and let apply o = o#A.f would work just the same. This scheme avoids unintended name clashes, increases modularity, and, I think, it could result in a more efficient implementation. Unfortunately, I'd expect that programmers would react very adversly to this unexpected additional notational burden. So there would be a need to alleviate that burden somehow. In the literature the above idea is sometimes called "stand-alone messages". See Peter Froehlich's work on Lagoona[1] for more information. -Chris [1]: Peter H. Froehlich, Andreas Gal, and Michael Franz. Supporting Software Composition at the Programming-Language Level. Science of Computer Programming, Special Issue on New Software Composition Concepts. Volume 56, Numbers 1-2, Pages 41-57, April 2005. -- Chris Stork <> Support eff.org! <> http://www.ics.uci.edu/~cstork/ OpenPGP fingerprint: B08B 602C C806 C492 D069 021E 41F3 8C8D 50F9 CA2F ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Execution time of class versus record 2007-06-24 15:14 Execution time of class versus record tmp123 2007-06-24 15:29 ` [Caml-list] " Jon Harrop @ 2007-06-26 13:35 ` Sam Steingold 2007-06-26 16:29 ` [Caml-list] " Quôc Peyrot 1 sibling, 1 reply; 20+ messages in thread From: Sam Steingold @ 2007-06-26 13:35 UTC (permalink / raw) To: tmp123; +Cc: caml-list -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 tmp123@menta.net wrote: > Hello, > > I've tried to implement two equivalent small programs, the one using > class, the other one using records. The resulting execution times says > that class are 7-8 times slower than record (compiled with ocamlopt in a > Intel machine). As other have explained, classes use hash table lookup per slot access, while records access fields by offsets computed at compile-time. > Please, knows someone what I'm doing wrong? > let t0 = Unix.gettimeofday () in > Printf.printf "elapsed = %f\n" (Unix.gettimeofday() -. t0) Unix.gettimeofday is "wall clock". Unix.times is "CPU time". use the latter to time your programs because the former depends on the machine load at the time of the test while the latter does not. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.6 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFGgRYIPp1Qsf2qnMcRAiC5AJkBPG/XrrH3mSZuP+YFTtLk+xF4YACdGmdF zijSDKnxkm6BIpXDQ+DkLwE= =lchS -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Re: Execution time of class versus record 2007-06-26 13:35 ` Sam Steingold @ 2007-06-26 16:29 ` Quôc Peyrot 0 siblings, 0 replies; 20+ messages in thread From: Quôc Peyrot @ 2007-06-26 16:29 UTC (permalink / raw) To: caml-list On Jun 26, 2007, at 3:35 PM, Sam Steingold wrote: >> Please, knows someone what I'm doing wrong? >> let t0 = Unix.gettimeofday () in >> Printf.printf "elapsed = %f\n" (Unix.gettimeofday() -. t0) > > Unix.gettimeofday is "wall clock". > Unix.times is "CPU time". > use the latter to time your programs because the former depends on the > machine load at the time of the test while the latter does not. In my experience, you need both. Thread locks, NFS latency, load and so on can indeed impact the wall clock but it is ultimately what the customers are seeing. If you don't measure it, you might be missing bugs or possible IO optimizations. Some code might be looking perfectly fine in CPU time, but be catastrophic in real wall clock due to various reasons. But you also need the CPU Time to make sense of the wall clock time. Once a slow part of the code is identified (using wall clock) and once load or IO problems have been ruled out, it's good to use the CPU time to measure any optimizations done. What I meant is: - most of the time, if the machine is not really overloaded CPU Time ~= wall clock In this case, it's good to only look at the CPU Time - If you see that overall, on all the measures in all parts of the program there is a huge difference between CPU and wall clock, then it is probably a general load problem - But, you might see a huge difference only in certain part of the program, in such cases, it should be investigated. If you only measure wall clock, or CPU Time, you might just miss some part of the big picture. My 2 cents -- Best Regards, Quôc ^ permalink raw reply [flat|nested] 20+ messages in thread
[parent not found: <20070626065522.6175FBC77@yquem.inria.fr>]
* Re: Execution time of class versus record [not found] <20070626065522.6175FBC77@yquem.inria.fr> @ 2007-06-26 7:36 ` David Allsopp 2007-06-26 8:05 ` [Caml-list] " Nicolas Pouillard 0 siblings, 1 reply; 20+ messages in thread From: David Allsopp @ 2007-06-26 7:36 UTC (permalink / raw) To: caml-list On Jun 26, 2007, at 08:53 AM, Loup Vaillant wrote: > > For the same reason, there is a difference between: > > > > type t = A of int * int > > > > and: > > > > type t = A of (int * int) > > Err, I don't get it : I see exactly the same thing (written twice) here. > > Are you telling that : > type t = A of int * int <==> type t = (A of int) * int > >? The type declarations are different - the top-level reports a different type in each case! The brackets matter because they tell O'Caml how many *arguments* the constructor A will take and so affect the internal representation. With the first type declaration, A(1, 2) is a 2-argument constructor and the value will be represented internally as a 2-field block with tag 0 with field 0 containing 1 and field 1 containing 2. This means that this code wouldn't work: let foo = (1, 2) in A foo but with the second type declaration it would. With the second type declaration, A (1, 2) is a 1-argument constructor and will be represented internally as a 1-field block with tag 0 with field 0 "pointing" to another 2-field block containing the 1 and 2. Section #18.3.4 of the manual explains the internal representation difference (esp. with ref to #18.3.6 where it is compared to Polymorphic Variants) but I was sure that there was an explicit reference in the manual to the difference between the type declarations but I can't find it now :( The confusion arises because the notation for arguments of a constructor and tuple construction look the same - I believe the "revised" syntax for O'Caml changes the way these are declared to make it clearer but I've never looked at it... David ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [Caml-list] Re: Execution time of class versus record 2007-06-26 7:36 ` David Allsopp @ 2007-06-26 8:05 ` Nicolas Pouillard 0 siblings, 0 replies; 20+ messages in thread From: Nicolas Pouillard @ 2007-06-26 8:05 UTC (permalink / raw) To: David Allsopp; +Cc: caml-list On 6/26/07, David Allsopp <dra-news@metastack.com> wrote: > On Jun 26, 2007, at 08:53 AM, Loup Vaillant wrote: > > > For the same reason, there is a difference between: > > > > > > type t = A of int * int > > > > > > and: > > > > > > type t = A of (int * int) > > [...] > I believe the "revised" syntax for O'Caml > changes the way these are declared to make it clearer but I've never looked > at it... > Exactly: type t = [ A of int and int ]; and type t = [ A of (int * int) ]; -- Nicolas Pouillard ^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2007-06-28 1:13 UTC | newest] Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-06-24 15:14 Execution time of class versus record tmp123 2007-06-24 15:29 ` [Caml-list] " Jon Harrop 2007-06-24 15:48 ` Till Varoquaux 2007-06-24 16:06 ` Arnaud Spiwack 2007-06-24 18:18 ` skaller 2007-06-24 18:29 ` Gerd Stolpmann 2007-06-24 18:51 ` Arnaud Spiwack 2007-06-24 19:11 ` Chris King 2007-06-25 3:25 ` Jon Harrop 2007-06-25 11:16 ` Arnaud Spiwack 2007-06-25 12:07 ` Jon Harrop 2007-06-25 23:59 ` Jonathan Bryant 2007-06-26 0:15 ` Chris King 2007-06-26 6:53 ` Loup Vaillant 2007-06-26 7:02 ` Jon Harrop 2007-06-26 17:07 ` Loup Vaillant 2007-06-28 1:13 ` Christian Stork 2007-06-26 13:35 ` Sam Steingold 2007-06-26 16:29 ` [Caml-list] " Quôc Peyrot [not found] <20070626065522.6175FBC77@yquem.inria.fr> 2007-06-26 7:36 ` David Allsopp 2007-06-26 8:05 ` [Caml-list] " Nicolas Pouillard
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox