[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Custom method_missing doesn't trap super call

Richard Dale

7/14/2003 8:00:00 PM

Yukihiro Matsumoto wrote:

> Hi,
>
> In message "Custom method_missing doesn't trap super call"
> on 03/07/15, Richard Dale <Richard_Dale@tipitina.demon.co.uk> writes:
>
> |The non existent call to 't.baz()' is trapped ok. But in MyClass.foobar()
> |the 'super' call gives a 'no superclass method' error rather than calling
> |Base.method_missing as I expected. Does anyone know if there a way of
> |trapping the super call?
>
> I feel like it's a bad idea in general, but without any particular
> reason. Let me think.
Perhaps I should explain more what about I was trying to do - I didn't want
to over complicate the problem description. I'm working on bindings to a
C++ gui library Qt, and use a C method_missing (in the C 'Qt' extension) to
forward the calls to the C++ methods from ruby. When virtual methods are
overriden in ruby, like QPushButton::paintEvent(), it uses rb_respond_to()
to see whether or not there is a ruby version of the method.

if (rb_respond_to(obj, rb_intern(methodName)) == 0) {
return false;
}
....
Otherwise if rb_respond_to() returns true, call ruby methods like
'paintEvent' below via rb_funcall2()

Then the call to 'super' needs to correctly invoke the C++ paintEvent()
method via the method_missing trap.


require 'Qt';

class MyClass < Qt::PushButton
def paintEvent(event)
printf("In paintEvent...\n")
super
end
end

a = Qt::Application.new(ARGV, ref nil);
hello = MyClass.new("Hello World", nil)
hello.resize(100, 30)
a.setMainWidget(hello)
hello.show()
a.exec()

> |Thanks for any help - I've just started with ruby - the syntax is really
> |nice and 'tidy' (ie un-C++ like :) ) The only other thing I got stuck
> |with is how to remove an item from a hash via C.
>
> Use rb_hash_delete(hash, key);
Ah.. thanks thats ideal - I couldn't find it in intern.h with the other
rb_hash functions, so I assumed it didn't exist.

-- Richard
17 Answers

matz

7/15/2003 5:28:00 AM

0

In message "Re: Custom method_missing doesn''t trap super call"
on 03/07/15, Richard Dale <Richard_Dale@tipitina.demon.co.uk> writes:

|Perhaps I should explain more what about I was trying to do - I didn''t want
|to over complicate the problem description. I''m working on bindings to a
|C++ gui library Qt, and use a C method_missing (in the C ''Qt'' extension) to
|forward the calls to the C++ methods from ruby. When virtual methods are
|overriden in ruby, like QPushButton::paintEvent(), it uses rb_respond_to()
|to see whether or not there is a ruby version of the method.

I understand what you want. But why use method_missing? If Qt has
finite set of methods, why don''t you define wrapper methods just as
Swig does?

This does not mean I''m refusing "method_missing for super". I''m still
thinking.

matz.

Jim Cain

7/15/2003 6:01:00 AM

0

Yukihiro Matsumoto wrote:

> In message "Re: Custom method_missing doesn''t trap super call"
> on 03/07/15, Richard Dale <Richard_Dale@tipitina.demon.co.uk> writes:
>
> |Perhaps I should explain more what about I was trying to do - I didn''t want
> |to over complicate the problem description. I''m working on bindings to a
> |C++ gui library Qt, and use a C method_missing (in the C ''Qt'' extension) to
> |forward the calls to the C++ methods from ruby. When virtual methods are
> |overriden in ruby, like QPushButton::paintEvent(), it uses rb_respond_to()
> |to see whether or not there is a ruby version of the method.
>
> I understand what you want. But why use method_missing? If Qt has
> finite set of methods, why don''t you define wrapper methods just as
> Swig does?
>
> This does not mean I''m refusing "method_missing for super". I''m still
> thinking.
>
> matz.
>
>

I just had occasion to invent a solution for this in something I was
working on. Unfortunately, I wasn''t paying enough attention to this
thread beforehand, so I don''t know if someone has already recommended a
solution similar to mine--or even worse, recommended against it. :)

My goal is to wrap the instance variable @obj so that, from the outside
of the Wrapper object, it responds exactly like the @obj would.

---------8<---------
class Wrapper

# don''t respond to any inherited public methods
(methods - [''__id__'', ''__send__'']).each do |meth|
begin
undef_method meth.intern
rescue
# ignore
end
end

def initialize(conn, klass, id)
@obj = ...
end

def method_missing(meth, *args)
@obj.__send__(meth, *args)
end
---------8<---------

Comments?


Brian Candler

7/15/2003 7:27:00 AM

0

On Tue, Jul 15, 2003 at 03:01:10PM +0900, Jim Cain wrote:
> My goal is to wrap the instance variable @obj so that, from the outside
> of the Wrapper object, it responds exactly like the @obj would.

<< snip code >>

> Comments?

It looks like you have reinvented the delegator pattern:
http://www.rubycentral.com/book/lib_pat...

Cheers,

Brian.

Richard Dale

7/15/2003 10:27:00 AM

0

Yukihiro Matsumoto wrote:

> In message "Re: Custom method_missing doesn''t trap super call"
> on 03/07/15, Richard Dale <Richard_Dale@tipitina.demon.co.uk> writes:
>
> |Perhaps I should explain more what about I was trying to do - I didn''t
> |want to over complicate the problem description. I''m working on bindings
> |to a C++ gui library Qt, and use a C method_missing (in the C ''Qt''
> |extension) to forward the calls to the C++ methods from ruby. When
> |virtual methods are overriden in ruby, like QPushButton::paintEvent(), it
> |uses rb_respond_to() to see whether or not there is a ruby version of the
> |method.
>
> I understand what you want. But why use method_missing? If Qt has
> finite set of methods, why don''t you define wrapper methods just as
> Swig does?
The code is based on the PerlQt bindings project which use perl autoloading
to do what I want to do with method_missing in ruby. The clever thing about
it that it allows you to write adaptors for a language independent backend
library called ''Smoke'', with very little code. I''ve just started with the
perlguts code in the perl adaptor and hacked it to work the same way in
ruby. It already does quite a lot - the paintEvent example works apart from
the ''super'' call - everything else is fine.

With the Swig approach you can''t call protected methods, you can''t override
virtual methods, and it doesn''t have a mechanism for dealing with method
overloading very well (particularly important with constructors). With
Smoke I get all that for free, and I don''t even need to parse any
headers/write interfaces etc.

> This does not mean I''m refusing "method_missing for super". I''m still
> thinking.
OK no problem - but from the method names, maybe the perl autoload feature
was intended to load native methods on demand, but perhaps method_missing
was aimed at custom error trapping?

-- Richard

Richard Dale

7/15/2003 10:28:00 AM

0

Jim Cain wrote:

> Brian Candler wrote:
>
>> On Tue, Jul 15, 2003 at 03:01:10PM +0900, Jim Cain wrote:
>>
>>>My goal is to wrap the instance variable @obj so that, from the outside
>>>of the Wrapper object, it responds exactly like the @obj would.
>>
>>
>> << snip code >>
>>
>>>Comments?
>>
>>
>> It looks like you have reinvented the delegator pattern:
>> http://www.rubycentral.com/book/lib_pat...
>>
>> Cheers,
>>
>> Brian.
>>
>>
>
> Well crap, wouldn''t you know... I guess I need to do some more exploring
> through Ruby resources.
But thanks - I''ll experiment with the delegator suggestions - I think this
is a fun problem to try and solve somehow..

-- Richard

Brian Candler

7/15/2003 11:41:00 AM

0

On Tue, Jul 15, 2003 at 07:36:13PM +0900, Richard Dale wrote:
> >> It looks like you have reinvented the delegator pattern:
> >> http://www.rubycentral.com/book/lib_pat...
> >>
> >> Cheers,
> >>
> >> Brian.
> >>
> >>
> >
> > Well crap, wouldn''t you know... I guess I need to do some more exploring
> > through Ruby resources.
> But thanks - I''ll experiment with the delegator suggestions - I think this
> is a fun problem to try and solve somehow..

Absolutely. I kind of "discovered" delegation too, and found it gives you a
great way to build objects out of components - much more flexible than
subclassing, and neatly sidesteps a lot of philosophical issues with
subclassing too.

Cheers,

Brian.

Lyle Johnson

7/15/2003 12:58:00 PM

0

Richard Dale wrote:

> With the Swig approach you can''t call protected methods, you can''t override
> virtual methods, and it doesn''t have a mechanism for dealing with method
> overloading very well (particularly important with constructors). With
> Smoke I get all that for free, and I don''t even need to parse any
> headers/write interfaces etc.

For the record, SWIG 1.3.20 will provide support for overriding C++
virtual methods with Ruby instance methods; this code is already
available in the SWIG development CVS. Method overloading has been
available since SWIG version 1.3.14 or so, and works very well for
constructors as well as regular functions.

On a side note, I hadn''t heard about Smoke, and so I was doing some
quick googling for it. It sounds pretty cool. Am I basically correct
that it is a Qt (or maybe Qt+KDE) specific library that can be used to
build different language bindings to Qt? In other words, it is not a
general purpose "wrapper" generator like SWIG?

Richard Dale

7/15/2003 1:27:00 PM

0

Brian Candler wrote:

> On Tue, Jul 15, 2003 at 07:36:13PM +0900, Richard Dale wrote:
>> >> It looks like you have reinvented the delegator pattern:
>> >> http://www.rubycentral.com/book/lib_pat...
>> >>
>> >> Cheers,
>> >>
>> >> Brian.
>> >>
>> >>
>> >
>> > Well crap, wouldn''t you know... I guess I need to do some more
>> > exploring through Ruby resources.
>> But thanks - I''ll experiment with the delegator suggestions - I think
>> this is a fun problem to try and solve somehow..
>
> Absolutely. I kind of "discovered" delegation too, and found it gives you
> a great way to build objects out of components - much more flexible than
> subclassing, and neatly sidesteps a lot of philosophical issues with
> subclassing too.
I just tried adding this onto the end of the Example 2 of delegation in
Programming Ruby (page 468):

class FooBar < TicketOffice
def try_delegate_to_super()
puts "In try_delegate_to_super"
super
end
end

to = FooBar.new
puts to.sellTicket
to.try_delegate_to_super

So the superclass of FooBar is a delegator. When I ran it I got the
following output:

ruby trydelegate2.rb
Here is a ticket
In try_delegate_to_super
trydelegate2.rb:33:in `try_delegate_to_super'': super: no superclass method
`try_delegate_to_super'' (NameError)
from trydelegate2.rb:39

So although the SimpleDelegate class doesn''t use method_missing (my ruby
isn''t good enough to tell how it works yet), it isn''t possible to forward a
message to super this way either.

-- Richard

Brian Candler

7/15/2003 2:49:00 PM

0

On Tue, Jul 15, 2003 at 10:37:29PM +0900, Richard Dale wrote:
> So although the SimpleDelegate class doesn''t use method_missing (my ruby
> isn''t good enough to tell how it works yet), it isn''t possible to forward a
> message to super this way either.

But you can now forget about class hierarchies, and deal with delegation
hierarchies instead.

I find it''s simplest and most powerful to explicitly keep track of objects
you want to delegate to. Here''s a trivial example:

-------------------------------------------------------------------------
class Foo # the ''superclass''
def meth1
puts "meth1 in #{self.class}"
end
end

class Bar # the ''child'' class
def initialize
@sup = Foo.new
end
def meth2
puts "meth2 in #{self.class}"
end
def method_missing(msg,*args,&blk)
@sup.send(msg,*args,&blk)
end
end

c = Bar.new
c.meth1
c.meth2

#>> meth1 in Foo
#>> meth2 in Bar
-------------------------------------------------------------------------

The above example shows ''method_missing'' in class Bar to delegate to @sup -
you could also use SimpleDelegator with __setobj__ - but in practice I write
explicit delegation functions, i.e.

def meth1(*args)
@sup.meth1(*args)
end

This means I don''t have to worry about ''public'' and ''private'', because I
explicitly only allow certain messages through. Furthermore, this works
properly over DRb, which only forwards methods which are explicitly defined
in the receiver object (it won''t fall back to method_missing).

By building your application like this, you can choose to have multiple
objects to which you delegate - e.g. delegate some methods to one object and
some to another. You can write composite methods which use more than one
delegate object to perform their work. The delegate objects can be changed
dynamically at run-time too. You end up creating ''glue'' or ''facade'' objects
which make use of other objects to do their work, in a very natural way.

When I thought about it, I realised that subclassing and module mixins are
really just Ruby internal implementations of the delegator pattern. If that
built-in implementation does exactly what you need, then that''s OK; but if
you need more fine-grained control, you just implement the delegation
yourself.

Regards,

Brian.

Brian Candler

7/15/2003 2:56:00 PM

0

On Tue, Jul 15, 2003 at 11:48:48PM +0900, Brian Candler wrote:
> But you can now forget about class hierarchies, and deal with delegation
> hierarchies instead.
>
> I find it''s simplest and most powerful to explicitly keep track of objects
> you want to delegate to. Here''s a trivial example:

P.S. I forgot the issue about ''super'' which had been raised before, but when
you do explicit delegation the problem vanishes:

class Foo # the ''superclass''
def meth1
puts "meth1 in #{self.class}"
end
end

class Bar # the ''child'' class
def initialize
@sup = Foo.new
end
def meth1
puts "meth1 in #{self.class}"
@sup.meth1 # <-----
end
end

c = Bar.new
c.meth1

#>>meth1 in Bar
#>>meth1 in Foo

Of course you''re not limited to one ''parent'' object; you can decide to pass
to one or more objects which you hold a reference to.

Regards,

Brian.