caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Question about objects and method overriding
@ 2014-02-02 11:55 Tom Ridge
  2014-02-02 12:43 ` Jacques Garrigue
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Tom Ridge @ 2014-02-02 11:55 UTC (permalink / raw)
  To: caml-list

Dear caml-list,

With records, one can functionally update a field e.g. as

{ r with some_field=new_value }

And new_value may, of course, be a function.

With objects, is there similar functionality? e.g. can I write something like

{{ myobj with method some_method=new_method }}

?

Of course, I could copy the methods from myobj explicitly into a new
object (and set some_method to new_method), but I might not know all
the methods available on myobj, and even if I do this becomes
textually extremely verbose.

Of course, new_method cannot directly refer to self etc. Basically I
am using objects in a similar way to records, and would like to use
this functional record update feature.

Thanks

Tom

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-02 11:55 [Caml-list] Question about objects and method overriding Tom Ridge
@ 2014-02-02 12:43 ` Jacques Garrigue
  2014-02-02 12:50   ` Tom Ridge
  2014-02-03 10:35 ` Goswin von Brederlow
  2014-02-05 18:22 ` remy
  2 siblings, 1 reply; 9+ messages in thread
From: Jacques Garrigue @ 2014-02-02 12:43 UTC (permalink / raw)
  To: Tom Ridge; +Cc: OCaml Mailing List

On 2014/02/02 20:55, Tom Ridge wrote:

> Dear caml-list,
> 
> With records, one can functionally update a field e.g. as
> 
> { r with some_field=new_value }
> 
> And new_value may, of course, be a function.
> 
> With objects, is there similar functionality? e.g. can I write something like
> 
> {{ myobj with method some_method=new_method }}
> 
> ?
> 
> Of course, I could copy the methods from myobj explicitly into a new
> object (and set some_method to new_method), but I might not know all
> the methods available on myobj, and even if I do this becomes
> textually extremely verbose.
> 
> Of course, new_method cannot directly refer to self etc. Basically I
> am using objects in a similar way to records, and would like to use
> this functional record update feature.
> 
> Thanks
> 
> Tom


You can copy an object updating a value field, not a method field:

class point (x:int) = object val x = x method get = x method bump dx = {< x = x+dx >} end

You can use this for methods too, by having them call a function value field.
However, this kind of update is only available inside methods, which requires some thinking
when designing your code.

I agree that what you suggest would be nice to have.
There is no majore technical difficulty, but there would be some overhead.

	Jacques Garrigue

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-02 12:43 ` Jacques Garrigue
@ 2014-02-02 12:50   ` Tom Ridge
  0 siblings, 0 replies; 9+ messages in thread
From: Tom Ridge @ 2014-02-02 12:50 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: OCaml Mailing List

Thanks, that is what I feared. Added as feature request:

http://caml.inria.fr/mantis/view.php?id=6314

On 2 February 2014 12:43, Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> wrote:
> On 2014/02/02 20:55, Tom Ridge wrote:
>
>> Dear caml-list,
>>
>> With records, one can functionally update a field e.g. as
>>
>> { r with some_field=new_value }
>>
>> And new_value may, of course, be a function.
>>
>> With objects, is there similar functionality? e.g. can I write something like
>>
>> {{ myobj with method some_method=new_method }}
>>
>> ?
>>
>> Of course, I could copy the methods from myobj explicitly into a new
>> object (and set some_method to new_method), but I might not know all
>> the methods available on myobj, and even if I do this becomes
>> textually extremely verbose.
>>
>> Of course, new_method cannot directly refer to self etc. Basically I
>> am using objects in a similar way to records, and would like to use
>> this functional record update feature.
>>
>> Thanks
>>
>> Tom
>
>
> You can copy an object updating a value field, not a method field:
>
> class point (x:int) = object val x = x method get = x method bump dx = {< x = x+dx >} end
>
> You can use this for methods too, by having them call a function value field.
> However, this kind of update is only available inside methods, which requires some thinking
> when designing your code.
>
> I agree that what you suggest would be nice to have.
> There is no majore technical difficulty, but there would be some overhead.
>
>         Jacques Garrigue

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-02 11:55 [Caml-list] Question about objects and method overriding Tom Ridge
  2014-02-02 12:43 ` Jacques Garrigue
@ 2014-02-03 10:35 ` Goswin von Brederlow
  2014-02-03 12:24   ` Tom Ridge
  2014-02-03 13:55   ` Alain Frisch
  2014-02-05 18:22 ` remy
  2 siblings, 2 replies; 9+ messages in thread
From: Goswin von Brederlow @ 2014-02-03 10:35 UTC (permalink / raw)
  To: caml-list

On Sun, Feb 02, 2014 at 11:55:02AM +0000, Tom Ridge wrote:
> Dear caml-list,
> 
> With records, one can functionally update a field e.g. as
> 
> { r with some_field=new_value }
> 
> And new_value may, of course, be a function.
> 
> With objects, is there similar functionality? e.g. can I write something like
> 
> {{ myobj with method some_method=new_method }}
> 
> ?
> 
> Of course, I could copy the methods from myobj explicitly into a new
> object (and set some_method to new_method), but I might not know all
> the methods available on myobj, and even if I do this becomes
> textually extremely verbose.
> 
> Of course, new_method cannot directly refer to self etc. Basically I
> am using objects in a similar way to records, and would like to use
> this functional record update feature.
> 
> Thanks
> 
> Tom

On the source level you can change a method by inheriting the old
class and implementing the method again. But you seem to want to
change the method at runtime. Problem there is that all instances of a
class afaik have the same virtual table to dispatch methods. So
changing a methong in one instance would change it in all.

But why not dispatch the method through a value of the insance using a
closure?

class myobj = object
  val mutable call_fn = fun () -> ()
  method call = call_fn ()
  method set_call fn = call_fn <- fn
end

MfG
	Goswin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-03 10:35 ` Goswin von Brederlow
@ 2014-02-03 12:24   ` Tom Ridge
  2014-02-03 15:54     ` Goswin von Brederlow
  2014-02-03 13:55   ` Alain Frisch
  1 sibling, 1 reply; 9+ messages in thread
From: Tom Ridge @ 2014-02-03 12:24 UTC (permalink / raw)
  To: Goswin von Brederlow; +Cc: caml-list

The scenario might be: I don't have the ability to change the object
implementation to use an instance variable (perhaps the object comes
from a library I am using), or maybe I don't want to decide upfront
when I create the object, which methods can be overridden in this way
(i.e. I don't want to add explicit set_call methods for all functions
that I might want to override).


On 3 February 2014 10:35, Goswin von Brederlow <goswin-v-b@web.de> wrote:
> On Sun, Feb 02, 2014 at 11:55:02AM +0000, Tom Ridge wrote:
>> Dear caml-list,
>>
>> With records, one can functionally update a field e.g. as
>>
>> { r with some_field=new_value }
>>
>> And new_value may, of course, be a function.
>>
>> With objects, is there similar functionality? e.g. can I write something like
>>
>> {{ myobj with method some_method=new_method }}
>>
>> ?
>>
>> Of course, I could copy the methods from myobj explicitly into a new
>> object (and set some_method to new_method), but I might not know all
>> the methods available on myobj, and even if I do this becomes
>> textually extremely verbose.
>>
>> Of course, new_method cannot directly refer to self etc. Basically I
>> am using objects in a similar way to records, and would like to use
>> this functional record update feature.
>>
>> Thanks
>>
>> Tom
>
> On the source level you can change a method by inheriting the old
> class and implementing the method again. But you seem to want to
> change the method at runtime. Problem there is that all instances of a
> class afaik have the same virtual table to dispatch methods. So
> changing a methong in one instance would change it in all.
>
> But why not dispatch the method through a value of the insance using a
> closure?
>
> class myobj = object
>   val mutable call_fn = fun () -> ()
>   method call = call_fn ()
>   method set_call fn = call_fn <- fn
> end
>
> MfG
>         Goswin
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-03 10:35 ` Goswin von Brederlow
  2014-02-03 12:24   ` Tom Ridge
@ 2014-02-03 13:55   ` Alain Frisch
  2014-02-03 15:12     ` Tom Ridge
  1 sibling, 1 reply; 9+ messages in thread
From: Alain Frisch @ 2014-02-03 13:55 UTC (permalink / raw)
  To: Goswin von Brederlow, caml-list

On 02/03/2014 11:35 AM, Goswin von Brederlow wrote:
> On the source level you can change a method by inheriting the old
> class and implementing the method again. But you seem to want to
> change the method at runtime. Problem there is that all instances of a
> class afaik have the same virtual table to dispatch methods. So
> changing a methong in one instance would change it in all.

Well, nothing prevent you from creating a fresh copy of the table for 
the new object, as in:

let unsafe_override (o : 'a) (ov : < .. >) : 'a =
   let o = Obj.repr (Oo.copy o) in
   let meths = Obj.dup (Obj.field o 0) in
   Obj.set_field o 0 meths;
   let nmeths : int = Obj.magic (Obj.field meths 0) in

   let ov = Obj.repr ov in
   let new_meths = Obj.field ov 0 in
   let nnew_meths : int = Obj.magic (Obj.field new_meths 0) in
   let i = ref 0 and j = ref 0 in
   while !i < nmeths && !j < nnew_meths do
     let tag : int = Obj.magic (Obj.field meths (3 + 2 * !i)) in
     let ntag : int = Obj.magic (Obj.field new_meths (3 + 2 * !j)) in
     if tag < ntag then incr i
     else if ntag < tag then incr j
     else begin
       let f : _ -> _ = Obj.magic (Obj.field new_meths (2 + 2 * !j)) in
       Obj.set_field meths (2 + 2 * !i) (Obj.magic (fun _ -> f ov));
       incr i;
       incr j
     end
   done;
   Obj.magic o


val unsafe_override : (< .. > as 'a) -> < .. > -> 'a = <fun>


This function returns a copy of its first argument (with the same type), 
where the methods which are also defined in the second argument are 
overridden with the implementation from the second argument (and when 
they are called, their "self" is the second argument).

This is type-unsafe because one should enforce that methods common to 
the two objects have the same type (and that there is no clash between 
the hash value of their other methods).  Is there a user-land hack to 
encode this property (or a stronger one, such as the type of the first 
argument be an extension of the type of the second argument)?

For a given list of methods, one can define safe (I believe!) instances 
of unsafe_override, for instance:

let override_x_y : (< x : 'x; y : 'y; .. > as 'this) -> < x : 'x; y : 'y 
 > -> 'this = unsafe_override;;


This function can be used to override methods x and y of an object 
having these methods and potentially more.

Some syntactic sugar could automate this a little bit.  For instance, 
with extension points, one could use a -ppx filter to rewrite:

  [#oo_override x y]

into:

(unsafe_override : (< x : 'x; y : 'y; .. > as 'this) -> < x : 'x; y : 'y 
 > -> 'this)

(with same more unique names for the generated type variables)




Alain

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-03 13:55   ` Alain Frisch
@ 2014-02-03 15:12     ` Tom Ridge
  0 siblings, 0 replies; 9+ messages in thread
From: Tom Ridge @ 2014-02-03 15:12 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Goswin von Brederlow, caml-list

>
> For a given list of methods, one can define safe (I believe!) instances of
> unsafe_override, for instance:
>
> let override_x_y : (< x : 'x; y : 'y; .. > as 'this) -> < x : 'x; y : 'y >
> -> 'this = unsafe_override;;
>
>
> This function can be used to override methods x and y of an object having
> these methods and potentially more.
>

I think this is exactly what I want! Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-03 12:24   ` Tom Ridge
@ 2014-02-03 15:54     ` Goswin von Brederlow
  0 siblings, 0 replies; 9+ messages in thread
From: Goswin von Brederlow @ 2014-02-03 15:54 UTC (permalink / raw)
  To: caml-list

On Mon, Feb 03, 2014 at 12:24:51PM +0000, Tom Ridge wrote:
> The scenario might be: I don't have the ability to change the object
> implementation to use an instance variable (perhaps the object comes
> from a library I am using), or maybe I don't want to decide upfront
> when I create the object, which methods can be overridden in this way
> (i.e. I don't want to add explicit set_call methods for all functions
> that I might want to override).
> 
> 
> On 3 February 2014 10:35, Goswin von Brederlow <goswin-v-b@web.de> wrote:
> > On Sun, Feb 02, 2014 at 11:55:02AM +0000, Tom Ridge wrote:
> >> Dear caml-list,
> >>
> >> With records, one can functionally update a field e.g. as
> >>
> >> { r with some_field=new_value }
> >>
> >> And new_value may, of course, be a function.
> >>
> >> With objects, is there similar functionality? e.g. can I write something like
> >>
> >> {{ myobj with method some_method=new_method }}
> >>
> >> ?
> >>
> >> Of course, I could copy the methods from myobj explicitly into a new
> >> object (and set some_method to new_method), but I might not know all
> >> the methods available on myobj, and even if I do this becomes
> >> textually extremely verbose.
> >>
> >> Of course, new_method cannot directly refer to self etc. Basically I
> >> am using objects in a similar way to records, and would like to use
> >> this functional record update feature.
> >>
> >> Thanks
> >>
> >> Tom
> >
> > On the source level you can change a method by inheriting the old
> > class and implementing the method again. But you seem to want to
> > change the method at runtime. Problem there is that all instances of a
> > class afaik have the same virtual table to dispatch methods. So
> > changing a methong in one instance would change it in all.
> >
> > But why not dispatch the method through a value of the insance using a
> > closure?
> >
> > class myobj = object
> >   val mutable call_fn = fun () -> ()
> >   method call = call_fn ()
> >   method set_call fn = call_fn <- fn
> > end
> >
> > MfG
> >         Goswin

class myobj = object
  inherit libobj as parent
  val mutable call_fn = fun () -> parent#call
  method call = call_fn ()
  method set_call fn = call_fn <- fn
end

You can always override the method of a given class.

But see other mail for the award deserving Obj.magic hack to change a
method on the fly.

MfG
	Goswin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [Caml-list] Question about objects and method overriding
  2014-02-02 11:55 [Caml-list] Question about objects and method overriding Tom Ridge
  2014-02-02 12:43 ` Jacques Garrigue
  2014-02-03 10:35 ` Goswin von Brederlow
@ 2014-02-05 18:22 ` remy
  2 siblings, 0 replies; 9+ messages in thread
From: remy @ 2014-02-05 18:22 UTC (permalink / raw)
  To: caml-list

Tom,

I am afraid that what you would like to do is unsafe. Consider the following
example:

     class a  = object method a = 1 end
     class ac = object (self : 'a) method a = 1 method c = 3 end
     class ab = object method a = 1 method b = new a end

     class abc = object (self : 'a)
       method a  = (self # b) # c
       method b = self
       method c = 2
     end

     let bug =
       let abc = new abc in
       let ab = (abc :> ab) in
       let ab' : ab = (ab with b = new a)
       ab' # a

This is typable in OCaml if you replace the penultimate line by let ab' = ab
According to your proposal, the penultimate line should typecheck as well
because we change method b of type a by a method of the same type.

However, the evaluation of bug creates a new object ab' with methods a, b,
and c but where b returns an object a' with a single method a.  Therefore,
the evaluation of ab' # a will reduce to ab' # b # c then to a' # c which
will break.

----------------

The problem is that methods may receive self as argument, but this is not
traced in the object types---only in the class types.

If you replace method override by field override with a val call_b
and a method set_b as suggested, typechecking will break because
the type of self will then appear contra-variantly in method set_b which
will prevent subtyping (abc : ab).

In order to typecheck method overriding safely, one has to prevent the use
of subtyping altogether or track it field by field, but this quickly becomes
very tricky.

See for instance "From classes to objects via subtyping"
http://cristal.inria.fr/~remy/publications_abstracts.html#Remy/classes-to-objects/esop

         Didier

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-02-05 18:22 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-02 11:55 [Caml-list] Question about objects and method overriding Tom Ridge
2014-02-02 12:43 ` Jacques Garrigue
2014-02-02 12:50   ` Tom Ridge
2014-02-03 10:35 ` Goswin von Brederlow
2014-02-03 12:24   ` Tom Ridge
2014-02-03 15:54     ` Goswin von Brederlow
2014-02-03 13:55   ` Alain Frisch
2014-02-03 15:12     ` Tom Ridge
2014-02-05 18:22 ` remy

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).