From: Avi Bryant Date: 2001-03-06T11:16:08+09:00 Subject: [ruby-talk:12074] Re: Ruby & AOP A lot of the discussion has been hovering around basically this question - what would be the cleanest/most useful primitive for doing AOP or AOP-like things? advice.c was my first try at such a thing, but I'm not entirely happy with it. Something like "called" might be good - ideally usage would be something like class Foo def called(method, *args, &block) #do stuff (including manipulation of args) retval = send(method, args) &block #do more stuff return retval end end It's a little messier than the way advice.c currently works, but since the primitive would most likely be used only within higer level AOP packages, maybe that doesn't actually matter - and it would probably fix the has_block? bug in advice.c that Guy pointed out. The implementation exactly as I describe it above, however, wouldn't work - it would end up in infinite recursion of send/called/send/called. The way both AspectR and advice.c solve this is to store the "real" method under a mangled name, so that in fact "called" would look either like def called(mangled_method, *args, &block) #do stuff (unmangling method if needed) send(mangled_method, args) &block end or def called(method, *args, &block) #do stuff send(mangle(method), args) &block end Actually implementing this would be very easy, it would just be a simplified advice.c. Thoughts, anyone? On Tue, 6 Mar 2001, Dennis Decker Jensen wrote: > So here is my main thougth: What about adding another callback named > "called"? Object.called seems like the right place..(??) > > It could be used something like this (wild fantasy code snippet): > --------------------- > class Thing > attr_reader :x > > def initialize(x, y) > @x,@y = x, y > end > > def printXAndY > print "x: #{@x} y: #{@y}\n" > end > > def Thing.called(object, method, returned_object, *args) > puts "In class method: " > print "#{object}.#{method}(#{args}\n" > end > > def called(object, method, returned_object, *args) > puts "In instance method: " > print "#{object}.#{method}(#{args})\n" > args[0] = 7 if method =~ "printXandY" > end > end > > t = Thing.new(12,24) # would generate something like: > In class method: Thing.new(12, 24) > In instance method: t.initialize(12, 24) > > t.printXandY # would generate something like: > In instance method: t.printXandY() > > puts t.x # would generate something like: > In instance method: t.x() > 7 > --------------------- > > It looks nice from a usage point of view. Pure Star Trek! Is it feasible? > > The idea is to pass arguments similar to the ones passed on in AspectR and > be able to change the arguments in place. Oh - wait - there is going to be a > problem with that... Ruby variable assignment only changes the reference and > not the object itself. > > Sigh! I'm sorry about that. > > I'm afraid though that I haven't got a clue regarding the implementation or > issues involved. Does anyone have knowledge to see if it could be possible > somehow? Would it be worth the effort? > > Dennis Decker Jensen >