[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Calling methods in the inheritance chain...

gga

3/1/2005 6:25:00 AM

class A
def a
puts "A::a()"
end
end

class B < A
def a
super
end
end

class C < B
def other
A#a() # no cigar... A's methods cannot be called
end
end

----
Ok, this has been discussed in the past, but... just want to verify
that ruby is still so poor in this area.
I want to be able to call functions like in C++ or in python, where
super is pretty much not restricted to just calling the same method nor
a single level in the inheritance chain.
I can work around the issue using an alias somewhere in B, but this is
a pretty horrible idea both in terms of design and mantainabilty of the
code in the long run.
Is this the best that ruby can do?

Basically, in python you can do:
class A:
def a(self):
print "A::a()"

class B(A):
def a(self):
print "B::a()"
A.a(self) # calls A.a()

class C(B):
def b(self):
print "C::b()"
B.a(self)

or even (in newer pythons 2.3+):
class A:
def a(self):
print "A::a()"

class B(A):
def a(self):
print "B::a()"
super(B, self).a() # call's B's ancestor's a() method, whatever
it may be

class C(B):
def b(self):
print "C::b()"
B.a(self)
---------------------------------
It seems to me that ruby should allow for just doing the logical:
class B < A
def a()
super#a() or A#b()
end
end
where I use # as rdoc/ri uses it, not as a comment (not too crazy about
that syntax, thou).

5 Answers

Florian Gross

3/1/2005 8:33:00 AM

0

gga wrote:

> class A
> def a
> puts "A::a()"
> end
> end
>
> class B < A
> def a
> super
> end
> end
>
> class C < B
> def other
> A#a() # no cigar... A's methods cannot be called
> end
> end

Use A.instance_method(:a).bind(self).call().

Note that this has a longish syntax which means it is an usual thing to
do in Ruby.

Robert Klemme

3/1/2005 9:23:00 AM

0


"Florian Gross" <flgr@ccan.de> schrieb im Newsbeitrag
news:38inm9F5ml1bfU1@individual.net...
> gga wrote:
>
> > class A
> > def a
> > puts "A::a()"
> > end
> > end
> >
> > class B < A
> > def a
> > super
> > end
> > end
> >
> > class C < B
> > def other
> > A#a() # no cigar... A's methods cannot be called
> > end
> > end
>
> Use A.instance_method(:a).bind(self).call().
>
> Note that this has a longish syntax which means it is an usual thing to
> do in Ruby.

IMHO this is an indication of poor class design. "super" is usually
sufficient and in a scenario like this, you can easily refactor (if you
have access to the super class, and in Ruby's case you can do it even if
you don't by runtime changes).

# refactored
class A
def a() a_impl() end
protected
def a_impl() puts "A::a()" end
end

class B < A
def a() super end
end

class C < B
def other() a_impl() end
end

Regards

robert

gga

3/1/2005 10:07:00 AM

0

Thanks, Florian and Robert. I had indeed ended up doing refactoring as
the easiest solution.


However, I admit not being too crazy about that as a general solution,
as that can easily lead to needing tons of, relatively speaking,
"useless" a_impl()-like methods on complex inheritance chains. Not
that it has been a problem for me yet, but... makes me go ...hmm...

Glad to know there is at least some obscure way of going around it,
too.

Also, I'm not sure I understand your comment about runtime changes.
How would you work around the issue if A was not ruby code. Would you
create an additional intermediate bridge class in ruby and have B
inherit from it?

Robert Klemme

3/1/2005 10:40:00 AM

0


"gga" <GGarramuno@aol.com> schrieb im Newsbeitrag
news:1109671603.644722.113290@g14g2000cwa.googlegroups.com...
> Thanks, Florian and Robert. I had indeed ended up doing refactoring as
> the easiest solution.
>
>
> However, I admit not being too crazy about that as a general solution,
> as that can easily lead to needing tons of, relatively speaking,
> "useless" a_impl()-like methods on complex inheritance chains. Not
> that it has been a problem for me yet, but... makes me go ...hmm...
>
> Glad to know there is at least some obscure way of going around it,
> too.
>
> Also, I'm not sure I understand your comment about runtime changes.
> How would you work around the issue if A was not ruby code. Would you
> create an additional intermediate bridge class in ruby and have B
> inherit from it?

I'm not 100% sure but this should work - even if A was not completely
implemented in Ruby:

class A
alias :a_impl :a
end

Then all sub classes can access a_impl - unless it's overridden of course.
:-)

An additional point of clarification: I do not mandate to have a and
a_impl for each public method. Instead I suggest to proper distribute
functionality across methods (with appropriate names). I know that this
is not always simple but it's good to keep that in mind when designing
base classes. Writing methods that do too much yields usually bad
modularity.

An example from a recent thread: someone suggested a method to cat input
to output. The suggested solution opened two (or more) files and copied
data from one file to the other. IMHO it's better to have separate
methods that do the file handling and the copying, with the copying method
working on open streams (IO). That way the copying can be reused in a
much wider range of applications.

# monolithic
def file_copy(out, *in)
File.open(out, "wb") do |o|
in.each do |fin|
File.open(fin,"rb") do |i|
while ( b = i.read(1024) )
o.write b
end
end
end
end
end

# modular
def stream_copy(in, out, size=1024)
while ( b = in.read(size) )
out.write b
end
end

def file_copy(out, *in)
File.open(out, "wb") do |o|
in.each do |fin|
File.open(fin, "rb") do |i|
stream_copy(i, o)
end
end
end
end

Kind regards

robert


florgro

3/1/2005 3:57:00 PM

0

Florian Gross <flgr@ccan.de> wrote:

> Note that this has a longish syntax which means it is an usual thing to
^^^^^
> do in Ruby.

This should have been "unusual".