I''ve been thinking about delegates and IronRuby. After playing around with trying to work with a delegate in Ruby (procs, lambdas and god-knows-what) I''ve come to the conclusion that delegates have to be supported in a more fundamental way than trying to make a block work as a delegate. First off, I think IR has to support adding and removing delegates via ''+='' and ''-=''. That''s how every other .NET language does it (IronPython included). It doesn''t seem right to use ''<<'' because there isn''t an equivalent ''>>'' (though I suppose you could define one). Anyway, you have to be able to remove a delegate as well as add one. Secondly, if you look at the way C# and VB address delegates, they use syntactic kludges to get round the fact that delegates are function pointers and are not to be invoked directly. C# uses the method name with no parentheses and VB uses AddressOf. There isn''t really an equivalent of a function pointer in Ruby. The most natural way of doing this, I guess is to use a symbol: x += EventHandler.new (:y) However, this doesn''t seem right because a) it won''t run and b) a symbol isn''t a function pointer. So possibly a better way might be to create a new class ''RubyDelegate'' (deriving from Delegate/MulticastDelegate) which takes the object and method name (or symbol) and returns a real .NET CLR delegate: x += EventHandler(RubyDelegate.new (self, "y")) or x += RubyDelegate.new (self, "y") Third: I notice that all the other languages (C# and VB at any rate, I can''t speak for things like F#) futz around with special delegate keywords to help as well as fooling around with the invokation syntax. Fourth: Delegates are plumbed into .NET at a pretty deep level. Most people, most of the time, don''t see them. But they are there - and I''ve used them quite a bit in communication systems. It seems to me that you have to recogize them in IronRuby at a similarly primitive level and not try to pretend that a delegate is equivalent to a block. A delegate is a function pointer. A block isn''t. Dermot -- Posted via http://www.ruby-forum.com/.
Dermot Hogan wrote:> I''ve been thinking about delegates and IronRuby. > > After playing around with trying to work with a delegate in Ruby (procs, > lambdas and god-knows-what) I''ve come to the conclusion that delegates > have to be supported in a more fundamental way than trying to make a > block work as a delegate. > > First off, I think IR has to support adding and removing delegates via > ''+='' and ''-=''. That''s how every other .NET language does it (IronPython > included). It doesn''t seem right to use ''<<'' because there isn''t an > equivalent ''>>'' (though I suppose you could define one). Anyway, you > have to be able to remove a delegate as well as add one.A problem you''ve missed here is that x += y and x -= y are (always) equivalent in Ruby to x = x + y and x = x - y. Unless + or - mutate the original object, now mutation will occur. Even in the case where they may be attributes: class Foo attr_accessor :a end f = Foo.new f.a = 1 f.a += 2 # equivalent to f.a = f.a + 2 The only way this might be able to work is if you defined + against a delegate to return the full collection of delegates, and then assignment updates the original list... class DelegateList def initialize(*delegates) @delegates = delegates end def +(other) DelegateList.new(other, *@delegates) end end f = Foo.new f.a = DelegateList.new(some_delegate) f.a += some_other_delegate Thoughts? We''ve had similar questions about how to handle event listener registration in JRuby, though there''s no legacy operator syntax to support in our case. - Charlie
On 10/25/07, Charles Oliver Nutter <charles.nutter at sun.com> wrote:> > > The only way this might be able to work is if you defined + against a > delegate to return the full collection of delegates, and then assignment > updates the original list...This doesn''t work for CLR events in the general case because events are opaque that way -- you can''t get a list of delegates that have been added to the event. -- Curt Hagenlocher curt at hagenlocher.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071025/7558f087/attachment.html
In general, any object that is somehow callable is a "function pointer" in DLR (this includes CLR delegates, CLR events, Ruby proc/lambda/Method, Python functions, JScript functions, etc.). All of them should just work in IronRuby. The main methods that would IronRuby see on a CLR are add, remove and call. Others are just syntactic sugar and aliases (<< is alias for add). << is as right for events as it is for Ruby Array IMO (there is also no method >> on array, it''s Array#delete). += -= are a little bit hacky from Ruby''s point of view IMO. They are more discoverable for a CLR guys though. So it might be good to support them as well. I don''t think we need RubyDelegate, you can write x << method(:y) x << C.instance_method(:y).bind(obj) or x += method(:y) x += C.instance_method(:y).bind(obj) x -= method(:y) if you will. Blocks/procs should also work: x { puts ''on click'' } x << lambda { puts ''on click'' } Tomas -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Dermot Hogan Sent: Thursday, October 25, 2007 1:39 PM To: ironruby-core at rubyforge.org Subject: [Ironruby-core] Delegates (agian) I''ve been thinking about delegates and IronRuby. After playing around with trying to work with a delegate in Ruby (procs, lambdas and god-knows-what) I''ve come to the conclusion that delegates have to be supported in a more fundamental way than trying to make a block work as a delegate. First off, I think IR has to support adding and removing delegates via ''+='' and ''-=''. That''s how every other .NET language does it (IronPython included). It doesn''t seem right to use ''<<'' because there isn''t an equivalent ''>>'' (though I suppose you could define one). Anyway, you have to be able to remove a delegate as well as add one. Secondly, if you look at the way C# and VB address delegates, they use syntactic kludges to get round the fact that delegates are function pointers and are not to be invoked directly. C# uses the method name with no parentheses and VB uses AddressOf. There isn''t really an equivalent of a function pointer in Ruby. The most natural way of doing this, I guess is to use a symbol: x += EventHandler.new (:y) However, this doesn''t seem right because a) it won''t run and b) a symbol isn''t a function pointer. So possibly a better way might be to create a new class ''RubyDelegate'' (deriving from Delegate/MulticastDelegate) which takes the object and method name (or symbol) and returns a real .NET CLR delegate: x += EventHandler(RubyDelegate.new (self, "y")) or x += RubyDelegate.new (self, "y") Third: I notice that all the other languages (C# and VB at any rate, I can''t speak for things like F#) futz around with special delegate keywords to help as well as fooling around with the invokation syntax. Fourth: Delegates are plumbed into .NET at a pretty deep level. Most people, most of the time, don''t see them. But they are there - and I''ve used them quite a bit in communication systems. It seems to me that you have to recogize them in IronRuby at a similarly primitive level and not try to pretend that a delegate is equivalent to a block. A delegate is a function pointer. A block isn''t. Dermot -- Posted via http://www.ruby-forum.com/. _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core
> I don''t think we need RubyDelegate, you can write > > x << method(:y) > x << C.instance_method(:y).bind(obj) > > or > > x += method(:y) > x += C.instance_method(:y).bind(obj) > x -= method(:y) > > if you will. > > Blocks/procs should also work: > > x { puts ''on click'' } > x << lambda { puts ''on click'' } > > TomasThis isn''t really what I mean. You need to be able to provide *syntactically* a delegate reference. So in C#, we have x += new EventHandler(mymethod) and in VB (I''m a bit rusty but something like this): x += new EventHandler(AddressOf mymethod) it''s not the same as adding a method to an object. The object already *has* the method. What you need to to do is add the *delegate* (a typesafe function pointer) into the delegate chain. I''m not an expert in any way in what you are doing in the DLR, but it doesn''t seem to me that this does it. A delegate is a different thing from a method object. ''method'' returns a method object which isn''t the same as a delegate (an instance of the Delegate class) - at least, I can''t add it into the delegate chain with the current version of IR. Are you saying that ''method'' will return a delegate? I''m not clear on this at all. Dermot -- Posted via http://www.ruby-forum.com/.
x << C.instance_method(:y).bind(obj) this piece of code does not add any method to anyone. It just passes C''s implementation of method "y" bound to object "obj" as an argument to object "x"''s "<<" method. No method adding, just indirection. On 10/25/07, Dermot Hogan <lists at ruby-forum.com> wrote:> > I don''t think we need RubyDelegate, you can write > > > > x << method(:y) > > x << C.instance_method(:y).bind(obj) > > > > or > > > > x += method(:y) > > x += C.instance_method(:y).bind(obj) > > x -= method(:y) > > > > if you will. > > > > Blocks/procs should also work: > > > > x { puts ''on click'' } > > x << lambda { puts ''on click'' } > > > > Tomas > > This isn''t really what I mean. You need to be able to provide > *syntactically* a delegate reference. > > So in C#, we have x += new EventHandler(mymethod) > > and in VB (I''m a bit rusty but something like this): > > x += new EventHandler(AddressOf mymethod) > > it''s not the same as adding a method to an object. The object already > *has* the method. What you need to to do is add the *delegate* (a > typesafe function pointer) into the delegate chain. > > I''m not an expert in any way in what you are doing in the DLR, but it > doesn''t seem to me that this does it. A delegate is a different thing > from a method object. ''method'' returns a method object which isn''t the > same as a delegate (an instance of the Delegate class) - at least, I > can''t add it into the delegate chain with the current version of IR. > > > Are you saying that ''method'' will return a delegate? I''m not clear on > this at all. > > > > Dermot > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core >
At the DLR level we can basically convert any callable object into a delegate. This is done by creating a dynamic method (that matches the delegates signature) that contains an embedded DynamicSite which performs a CallAction. That call action works through our IDynamicObject implementations (for complex language defined types), through language specific binders (Python wants to make newable-things callable), or through the base binder which provides the implementation for known type-systems (CLR types, COM types in the future, maybe IReflect/IExpando in the future?). So anything can be a delegate (it just might throw at call time)! (you might see 2 of these, I don''t think rubyforge liked my e-mail address before) -----Original Message----- From: ironruby-core-bounces at rubyforge.org [mailto:ironruby-core-bounces at rubyforge.org] On Behalf Of Dermot Hogan Sent: Thursday, October 25, 2007 2:51 PM To: ironruby-core at rubyforge.org Subject: Re: [Ironruby-core] Delegates (agian)> I don''t think we need RubyDelegate, you can write > > x << method(:y) > x << C.instance_method(:y).bind(obj) > > or > > x += method(:y) > x += C.instance_method(:y).bind(obj) > x -= method(:y) > > if you will. > > Blocks/procs should also work: > > x { puts ''on click'' } > x << lambda { puts ''on click'' } > > TomasThis isn''t really what I mean. You need to be able to provide *syntactically* a delegate reference. So in C#, we have x += new EventHandler(mymethod) and in VB (I''m a bit rusty but something like this): x += new EventHandler(AddressOf mymethod) it''s not the same as adding a method to an object. The object already *has* the method. What you need to to do is add the *delegate* (a typesafe function pointer) into the delegate chain. I''m not an expert in any way in what you are doing in the DLR, but it doesn''t seem to me that this does it. A delegate is a different thing from a method object. ''method'' returns a method object which isn''t the same as a delegate (an instance of the Delegate class) - at least, I can''t add it into the delegate chain with the current version of IR. Are you saying that ''method'' will return a delegate? I''m not clear on this at all. Dermot -- Posted via http://www.ruby-forum.com/. _______________________________________________ Ironruby-core mailing list Ironruby-core at rubyforge.org http://rubyforge.org/mailman/listinfo/ironruby-core
Charles Oliver Nutter wrote:> Dermot Hogan wrote: >> equivalent ''>>'' (though I suppose you could define one). Anyway, you >> have to be able to remove a delegate as well as add one. > > A problem you''ve missed here is that x += y and x -= y are (always) > equivalent in Ruby to x = x + y and x = x - y. Unless + or - mutate the > original object, now mutation will occur. >In .NET C# etc, the += and -= for delegates don''t really mean the same as they do in other contexts. They means ''add/remove'' a delegate into/from the delegate queue. You can''t say x = new EventHandler(mymethod) all you can do is add/remove. It''s another example of syntactic kluging IMO. It does work well in practise, though.> > Thoughts? We''ve had similar questions about how to handle event listener > registration in JRuby, though there''s no legacy operator syntax to > support in our case.Yes - I suppose so. You still have to add the address of the listener into the system in some way. Similar problem, but I think delegates are a bit trickier - they aren''t just function pointers; they carry other information as well. All .NET languages seem to treat them specially. Dermot -- Posted via http://www.ruby-forum.com/.
On 10/25/07, Dermot Hogan <lists at ruby-forum.com> wrote:> > In .NET C# etc, the += and -= for delegates don''t really mean the same > as they do in other contexts. They means ''add/remove'' a delegate > into/from the delegate queue. You can''t say > > x = new EventHandler(mymethod) > > all you can do is add/remove. It''s another example of syntactic kluging > IMO. It does work well in practise, though.This is actually a fundamental property of events on a CLR / IL level. Events are exposed as a pair of functions to add a handler and remove a handler. The reason for this is efficiency; if every Control in a Windows Forms application defined a slot for each of its events, you''d have an immense number of slots defined -- even though most of them would effectively have a value of null. -- Curt Hagenlocher curt at hagenlocher.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071025/97fa8bb7/attachment.html
On 10/25/07, Dermot Hogan <lists at ruby-forum.com> wrote:> > You can''t say > > x = new EventHandler(mymethod)I was trying to avoid writing this, but my inner pedant simply won''t let go. There''s a difference between delegates and events. A delegate is simply a bound function pointer, and it''s perfectly legal to do a straightforward assignment as above. An event is basically a published endpoint to which you subscribe and unsubscribe by adding and removing your delegate. The two are obviously related but not the same, and what we seem to be talking about here specifically involves events. I feel much better now. :) -- Curt Hagenlocher curt at hagenlocher.org -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071025/37b292fc/attachment.html
Dermot Hogan wrote:> So in C#, we have x += new EventHandler(mymethod) > > and in VB (I''m a bit rusty but something like this): > > x += new EventHandler(AddressOf mymethod) >The syntax for VB event handlers is AddHandler x.myevent, AddressOf mymethod assuming that the event being handled here is myevent. -- Posted via http://www.ruby-forum.com/.
Joe Chung wrote:> The syntax for VB event handlers is > > AddHandler x.myevent, AddressOf mymethod > > assuming that the event being handled here is myevent.Thanks! My VB is rustier than I''d assumed :) Dermot -- Posted via http://www.ruby-forum.com/.
I don''t know if it''s relevant or not, but the VB Windows Forms designer doesn''t generate anything like this anyway. It looks like: Private Sub x_myevent() Handles x.myevent End Sub The compiler wires up the delegates. On 10/26/07, Joe Chung <lists at ruby-forum.com> wrote:> > Dermot Hogan wrote: > > So in C#, we have x += new EventHandler(mymethod) > > > > and in VB (I''m a bit rusty but something like this): > > > > x += new EventHandler(AddressOf mymethod) > > > The syntax for VB event handlers is > > AddHandler x.myevent, AddressOf mymethod > > assuming that the event being handled here is myevent. > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Ironruby-core mailing list > Ironruby-core at rubyforge.org > http://rubyforge.org/mailman/listinfo/ironruby-core >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/ironruby-core/attachments/20071026/58a3eac6/attachment.html
Curt Hagenlocher wrote:> On 10/25/07, Dermot Hogan <lists at ruby-forum.com> wrote: > > > I was trying to avoid writing this, but my inner pedant simply won''t let > go. There''s a difference between delegates and events. A delegate is > simply a bound function pointer, and it''s perfectly legal to do a > straightforward assignment as above. An event is basically a published > endpoint to which you subscribe and unsubscribe by adding and removing > your > delegate. The two are obviously related but not the same, and what we > seem > to be talking about here specifically involves events. > > I feel much better now. :)Yes. I''ve lumped them together ... there are two parts to this. First, the add-assignment (which isn''t an assignment or an addition, but we''ll let that pass). I don''t really care whether this is a traditional += or a Ruby like << (which is more logical, I now think) so long as we have a delegate removal operator as well. The second part is the delegate constructor syntax, that is how you pass the name of the event handler itself to the System::EventHandler constructor. All I want is a reasonable way to doing this without involving blocks. I''d be quite happy to settle for this: x << System::EventHandler(self, :y) whatever it is, the arguments have to be acceptable to the .NET System::EventHandler API. What I''ve been trying to point out is that different languages (VB, C#, IronPython, ...) do this in slightly different ways, but whatever they do, they don''t use anything convoluted. However they do it, it''s clear what''s going on. Dermot -- Posted via http://www.ruby-forum.com/.
Eric Nicholson wrote:> I don''t know if it''s relevant or not, but the VB Windows Forms designer > doesn''t generate anything like this anyway. It looks like: > > Private Sub x_myevent() Handles x.myevent > End Sub > > The compiler wires up the delegates.Your code is syntactic sugar that generates AddHandler Me.myevent, New EventHandler(AddressOf Me.x_myevent) You can check this out for yourself with Reflector. It is relevant, because here are two examples (within the same language even) of language-specific syntax for event handling delegates. I think it would be okay if IronRuby had Ruby-like syntax for delegates as well. -- Posted via http://www.ruby-forum.com/.