caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ 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; 22+ 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] 22+ messages in thread

* Re: Execution time of class versus record
       [not found] <20070626065522.6175FBC77@yquem.inria.fr>
@ 2007-06-26  7:36 ` David Allsopp
  0 siblings, 0 replies; 22+ 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] 22+ messages in thread

* Execution time of class versus record
@ 2007-06-24 15:20 tmp123
  0 siblings, 0 replies; 22+ messages in thread
From: tmp123 @ 2007-06-24 15:20 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] 22+ messages in thread

* Execution time of class versus record
@ 2007-06-24 15:18 tmp123
  0 siblings, 0 replies; 22+ messages in thread
From: tmp123 @ 2007-06-24 15:18 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] 22+ messages in thread

end of thread, other threads:[~2007-06-28  1:13 UTC | newest]

Thread overview: 22+ 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
2007-06-24 15:18 tmp123
2007-06-24 15:20 tmp123
     [not found] <20070626065522.6175FBC77@yquem.inria.fr>
2007-06-26  7:36 ` David Allsopp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).