Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

method search rule in 2.0?

0 views
Skip to first unread message

David Garamond

unread,
Apr 9, 2005, 5:34:53 AM4/9/05
to
I read:


http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=Ruby2.0MethodSearchRuleEnglish

and was feeling disturbed about this new Ruby2 behaviour.

class C
def process
# ...
util
end

def util
# ...
end
end

class CC < C
def util
# ...
end
end

CC.new.process # C#process expects C#util,
# but calls CC#util

Why is this a problem? Isn't it what people expect in OO? I'm not an OO
expert, but isn't this one of the supposedly unique feature/benefit of
OO: allowing old code to call new code. I believe it's called polymorphism?

Now Ruby2 wants to change so that 'util' in C method calls C#util and
'self.util' calls CC#util. I very much prefer 'self.util' to be the one
that calls C#util (and I don't think I'll ever use it a lot). The latter
is backwards compatible and how virtually all other languages behave.

Regards,
dave


Peter C. Verhage

unread,
Apr 9, 2005, 6:13:37 AM4/9/05
to
David Garamond wrote:
> Now Ruby2 wants to change so that 'util' in C method calls C#util and
> 'self.util' calls CC#util. I very much prefer 'self.util' to be the one
> that calls C#util (and I don't think I'll ever use it a lot). The latter
> is backwards compatible and how virtually all other languages behave.

I totally agree with you.

I think a better way of solving this problem is using private methods
which are only part of the class for which they are defined. If a
subclass defines a method (private, protected or public) with the same
name as the private method in the superclass then all calls to the
private method made by methods in the superclass call the private method
in the super class. All methods calls on the method in the subclass call
the method defined there. Public or protected methods defined in
superclasses can be overriden in subclasses and when they are called
from the superclass the overriden method will be called. I believe this
is the way Java and C++ (among others) work.

Regards,

Peter

David A. Black

unread,
Apr 9, 2005, 7:25:48 AM4/9/05
to
Hi --

I agree that the non-special case should be what it is now, and the
case where you don't want overriding should be the one that requires
something extra. But I don't think it should be based on overloading
"self" (and I believe having "self" refer to the class context, rather
than the object, is a kind of overloading). If this mechanism is
really necessary, I would rather see:

class C
def process
# ...

C#util
end
end

which is, I think, a more direct way of saying: protect this call from
overriding in subclasses. (Yes, everybody, I do know that this is
comment syntax and would require a parser change :-)


David

--
David A. Black
dbl...@wobblini.net


Csaba Henk

unread,
Apr 9, 2005, 8:05:18 AM4/9/05
to
On 2005-04-09, David A. Black <dbl...@wobblini.net> wrote:
> class C
> def process
> # ...
> C#util
> end
> end
>
> which is, I think, a more direct way of saying: protect this call from
> overriding in subclasses. (Yes, everybody, I do know that this is
> comment syntax and would require a parser change :-)

As by the ruby of today, how you can do the above is:

class C
def process
# ...

C.instance_method(:util).bind(self).call
end
end

Now you will agree that it is not particularly convenient; but this is
how to do it... But. It's sooo long that you can't help remembering the
occasion if you use it.

And I don't remember doing it more that one or two times. That is, my
experience suggests that it's not a particularly frequent pattern. Which
means I agree with those who like the present state of the art.

Csaba

Lionel Thiry

unread,
Apr 9, 2005, 11:22:30 AM4/9/05
to
David A. Black a écrit :

> I agree that the non-special case should be what it is now, and the
> case where you don't want overriding should be the one that requires
> something extra. But I don't think it should be based on overloading
> "self" (and I believe having "self" refer to the class context, rather
> than the object, is a kind of overloading). If this mechanism is
> really necessary, I would rather see:
>
> class C
> def process
> # ...
> C#util
> end
> end
>
> which is, I think, a more direct way of saying: protect this call from
> overriding in subclasses. (Yes, everybody, I do know that this is
> comment syntax and would require a parser change :-)
>
>
> David
>

class C
def process
# ...
C::util
end
end

equivalent to

class C
def process
# ...

self.C::util
end
end

equivalent to

class C
def process
# ...

self.(C::util)
end
end

--
Lionel Thiry

Trans

unread,
Apr 9, 2005, 12:13:18 PM4/9/05
to
Ah, this is interesting. In the AOP work I've been doing, something
along these lines is a absolute must inorder to prevent method name
clashes and thus have fully reusable Aspects. My solution was to have
another scoping mechinism akin to public, private, protected, called
"local". It differs in that methods defined in the local scope are
always called locally in the context of that module, but not in the
context of any other. For instance:

class C
def x ; 1 ; end
end

class D
def y ; x ; end
local
def x ; 2 ; end
end

d = D.new
d.y #=> 2
d.x #=> 1

T.

David A. Black

unread,
Apr 9, 2005, 12:26:12 PM4/9/05
to
This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

Lionel Thiry

unread,
Apr 9, 2005, 4:36:13 PM4/9/05
to
David A. Black a écrit :
> Hi --
>
> On Sun, 10 Apr 2005, Lionel Thiry wrote:
>
>> David A. Black a �crit :

>>
>>> I agree that the non-special case should be what it is now, and the
>>> case where you don't want overriding should be the one that requires
>>> something extra. But I don't think it should be based on overloading
>>> "self" (and I believe having "self" refer to the class context, rather
>>> than the object, is a kind of overloading). If this mechanism is
>>> really necessary, I would rather see:
>>>
>>> class C
>>> def process
>>> # ...
>>> C#util
>>> end
>>> end
>>>
>>> which is, I think, a more direct way of saying: protect this call from
>>> overriding in subclasses. (Yes, everybody, I do know that this is
>>> comment syntax and would require a parser change :-)
>>>
>>>
>>> David
>>>
>>
>> class C
>> def process
>> # ...
>> C::util
>
>
> That's different; that's a class method.

In present ruby, yes, C::util is identical to C.util.

But I was thinking of "C::util" as an explicit namespace specification, not as a
message sending to C object.

You talked about adding some "#" new operator could be inadequate as it is
usually used for comments. I was just indicating "::" could do the job.

Sorry for my lack of clarity.

>
>> end
>> end
>>
>> equivalent to
>>
>> class C
>> def process
>> # ...
>> self.C::util
>> end
>> end
>>
>> equivalent to
>>
>> class C
>> def process
>> # ...
>> self.(C::util)
>> end
>> end
>
>

> These last two don't really fit the dot semantics, and if they're
> alternatives to C::util, then they're dealing with a class method
> anyway (rather than the issue of limiting the effect of overriding
> instance methods).
>
> My suggestion of C#util is based on the common use of # to mean
> "instance method of the named class or module". It wouldn't require
> redefinition of the dot notation, nor overloading 'self' to be a
> boolean flag (as in the original proposal, where 'self' means both
> "the default object" and "don't redirect this to an overridden version
> of the method).

And what is your opinion, now, if you take for granted that "::" semantic is
redefined?

--
Lionel Thiry

David A. Black

unread,
Apr 9, 2005, 4:49:21 PM4/9/05
to
Hi --

On Sun, 10 Apr 2005, Lionel Thiry wrote:

>> [I wrote:]

> That's different; that's a class method.
>
> In present ruby, yes, C::util is identical to C.util.
>
> But I was thinking of "C::util" as an explicit namespace
> specification, not as a message sending to C object.
>
> You talked about adding some "#" new operator could be inadequate as
> it is usually used for comments. I was just indicating "::" could do
> the job.
>
>
>>

>> These last two don't really fit the dot semantics, and if they're
>> alternatives to C::util, then they're dealing with a class method
>> anyway (rather than the issue of limiting the effect of overriding
>> instance methods).
>>
>> My suggestion of C#util is based on the common use of # to mean
>> "instance method of the named class or module". It wouldn't require
>> redefinition of the dot notation, nor overloading 'self' to be a
>> boolean flag (as in the original proposal, where 'self' means both
>> "the default object" and "don't redirect this to an overridden
>> version
>> of the method).
>
> And what is your opinion, now, if you take for granted that "::"
> semantic is redefined?

I think it's much too big a change for something like this. It would
also lead to huge amounts of code breakage. (I don't use :: for
method calls myself, but it's used a fair amount.)

Paul Hanchett

unread,
Apr 9, 2005, 4:37:01 PM4/9/05
to

If I was writing class C, I would be surprised when CC#util got called,
but that is exactly the OO behavior you want sometimes. I think both
the naked call to util and self.util should be relative to the
/instantiated/ object.

If I really want to call C#util, why not say C::util? It seems like
anything else has compatibility problems...

Paul

David A. Black

unread,
Apr 9, 2005, 5:13:53 PM4/9/05
to
Hi --

I agree. That's why I don't like the proposed change to "self".

> If I really want to call C#util, why not say C::util? It seems like
> anything else has compatibility problems...

C::util is a class method call, but what we're talking about here
pertains to instance methods. The idea of C#util is not to call
C::util, but to call util on the instatiated object -- constraining
that call so that it is the #util defined in class C, not class CC.

class C
def x
puts "I'm the #x from C"
end

def y
x # call the most recently defined #x at the time of the call
end

def z
C#x # call the x defined in C, no matter what
end
end

class CC < C
def x
puts "I'm the #x from CC"
end
end

CC.new.y # I'm the #x from CC
CC.new.z # I'm the #x from C

Note that having a CC object "call the x defined in C" is different
from saying "Call the class method C.x" (which doesn't exist at all).

Trans

unread,
Apr 9, 2005, 5:45:01 PM4/9/05
to

David A. Black wrote:
>
> class C
> def x
> puts "I'm the #x from C"
> end
>
> def y
> x # call the most recently defined #x at the time of the
call
> end
>
> def z
> C#x # call the x defined in C, no matter what
> end
> end
>
> class CC < C
> def x
> puts "I'm the #x from CC"
> end
> end
>
> CC.new.y # I'm the #x from CC
> CC.new.z # I'm the #x from C
>

If you don't mind David, I think this is good example to show what I
mean by a local namespace too. The local namespace idea is sort like
the original idea (differentiating on using self or not) but remains
backward compatible.

class C
def x
puts "I'm the #x from C"
end

local :x # localize x to C

def y
self.x # call the most recently defined #x
# in this case using self forces a non-local call
end

def z
x # call the x defined in C, b/c x is local
end
end

class CC < C
def x
puts "I'm the #x from CC"
end
end

CC.new.y # I'm the #x from CC
CC.new.z # I'm the #x from C

Hope that makes my idea a bit clearer. This approach has an advantage
over notations like C#x also, in that modules can then be included into
a class' local space.

module CM
def x
puts "I'm the #x from CM"
end
end

class C
include_local CM


def x
puts "I'm the #x from C"
end

def z
x
end
end

CC.new.x # I'm the #x from C
CC.new.z # I'm the #x from CM

Note there isn't any name clash between the local and non-local x
methods (in fact that's the whole point) local methods are referenced
in there own namespace.

T.

Paul Hanchett

unread,
Apr 9, 2005, 5:56:24 PM4/9/05
to
David A. Black wrote:

>> If I really want to call C#util, why not say C::util? It seems like
>> anything else has compatibility problems...
>
>
> C::util is a class method call,

But if C#util is not defined as a with "def C.util ..." isn't it just a
regular method? Or is C::util really a different sort of call to the
class object?

> but what we're talking about here
> pertains to instance methods. The idea of C#util is not to call
> C::util, but to call util on the instatiated object -- constraining
> that call so that it is the #util defined in class C, not class CC.
>
> class C
> def x
> puts "I'm the #x from C"
> end
>
> def y
> x # call the most recently defined #x at the time of the call
> end
>
> def z
> C#x # call the x defined in C, no matter what
> end
> end
>
> class CC < C
> def x
> puts "I'm the #x from CC"
> end
> end
>
> CC.new.y # I'm the #x from CC
> CC.new.z # I'm the #x from C
>
> Note that having a CC object "call the x defined in C" is different
> from saying "Call the class method C.x" (which doesn't exist at all).

Allowing an inheriting class to call an ancestor method without
inheriting it (i.e., skipping the inheritance chain) is not a good idea,
I think. Of course with Ruby you can retroactively redefine existing
methods on instantiated objects, right? (I'm a Ruby NOOB, so I may have
that wrong!)

An underlying assumption about OOD is that ancestor classes don't need
to worry about descendent classes changing the meaning of methods
defined by the ancestors.

I think we will have to pick our poison-- Either there has to be a
declaration /in the class defintion/ whether a particular method is
virtual of not (C++), or we choose an object model where all methods are
virtual (Java and Python) or not (VB, I think).

Paul

David A. Black

unread,
Apr 9, 2005, 10:35:52 PM4/9/05
to
Hi --

On Sun, 10 Apr 2005, Paul Hanchett wrote:

> David A. Black wrote:
>
>>> If I really want to call C#util, why not say C::util? It seems like
>>> anything else has compatibility problems...
>>
>>
>> C::util is a class method call,
>
> But if C#util is not defined as a with "def C.util ..." isn't it just a
> regular method? Or is C::util really a different sort of call to the class
> object?

C#util is actually the constant C plus a comment :-) This is all
speculative; there's no C#util expression in reality.

I don't think that's what happening here (?).

> Of
> course with Ruby you can retroactively redefine existing methods on
> instantiated objects, right? (I'm a Ruby NOOB, so I may have that wrong!)

Yes. Well, it's not really retroactive -- the old method calls don't
get re-performed :-) It's perhaps better described as happening
dynamically. But, essentially, yes.

> An underlying assumption about OOD is that ancestor classes don't need to
> worry about descendent classes changing the meaning of methods defined by the
> ancestors.
>
> I think we will have to pick our poison-- Either there has to be a
> declaration /in the class defintion/ whether a particular method is virtual
> of not (C++), or we choose an object model where all methods are virtual
> (Java and Python) or not (VB, I think).

I don't think the area that was addressed originally by the "self"
redefinition idea was that broad, design-wise -- that is, the basic
object model isn't under review, but just something very specific.
It's the following scenario: your superclass, inside an instance
method, calls another of its instance methods, expecting a particular
behavior, but that behavior has been changed by a subclass.


David A. Black
dbl...@wobblini.net

Lionel Thiry

unread,
Apr 9, 2005, 10:42:00 PM4/9/05
to
David A. Black a écrit :

I use it for constants. Does anybody use it for something else?

If not, then only constants would be affected. And the namespace semantic
wouldn't change much how things work for constants, don't you think?

Or I am missing some points, somewhere, as usual. ;)

--
Lionel Thiry

David A. Black

unread,
Apr 9, 2005, 10:58:59 PM4/9/05
to
Hi --

On Sun, 10 Apr 2005, Lionel Thiry wrote:

>>> And what is your opinion, now, if you take for granted that "::" semantic
>>> is redefined?
>>
>>
>> I think it's much too big a change for something like this. It would
>> also lead to huge amounts of code breakage. (I don't use :: for
>> method calls myself, but it's used a fair amount.)
>>
>
> I use it for constants. Does anybody use it for something else?

ruby/1.8$ grep "::[a-z_]" `find . -name "*.rb"` | wc -l
1194

:-)

> If not, then only constants would be affected. And the namespace semantic
> wouldn't change much how things work for constants, don't you think?

I just think it would be awfully confusing.

Avdi Grimm

unread,
Apr 11, 2005, 11:58:26 AM4/11/05
to
David Garamond <li...@zara.6.isreserved.com> writes:

> Now Ruby2 wants to change so that 'util' in C method calls C#util and
> 'self.util' calls CC#util. I very much prefer 'self.util' to be the one
> that calls C#util (and I don't think I'll ever use it a lot). The latter
> is backwards compatible and how virtually all other languages behave.

I would have to agree. As an OO programmer, the current behaviour is
what I would expect. And I'd go so far as to say that it's the
"correct" behaviour. When I call #util, I'm not "expecting" C#util, I'm
expecting the *right* #util to be called, where the "right" #util is
defined as the one that preserves the invariants of whatever class
self is a member of. An contrived example of why this is important:

class A

...

def do_stuff
data = get_some_data()
store(data)
end

def store(data)
@mydata << data
end
end

class ThreadSafeA

...

def store(data)
@mutex.lock
@mydata << data
@mutex.unlock
end
end

a = ThreadSafeA.new
a.do_stuff

In this case if the call to do_stuff resulted in a call to A#store, it
would violate the thread-safety invariant promised by ThreadSafeA.

Maybe not the best example, but it's a pattern which permeates OO
design. It's the Strategy pattern, really: a superclass defines some
broad, high-level methods which are implemented in terms of more
granular support methods; and then the implementation strategy is
defined by subclassing it and overriding the suport methods.

Actually, in my mind applying the principle of least astonishment
would lead to expecting store and self.store to have identical
behaviour. I would expect to have to use something like super.store
or A::store in order to specify that I want the superclass version of
store.

--
ABG

Trans

unread,
Apr 11, 2005, 3:52:16 PM4/11/05
to

Avdi Grimm wrote:
> Actually, in my mind applying the principle of least astonishment
> would lead to expecting store and self.store to have identical
> behaviour. I would expect to have to use something like super.store
> or A::store in order to specify that I want the superclass version of
> store.

I have to agree with you. While making a distinction around the use of
self.x verses x seems reasonable to some degree (after all they are
written differently), the old ambiguity of x= raises it's ugly head. To
refresh, x= would be interpreted as a local variable assignment and not
a method call, thus requiring the use of self.x= instead. B/c of this
x= and self.x= must remain equivalent.

But lets say we do adopt a differnt syntax as you suggest. Of the
options I think David's suggestion of M#x is the most obvious since
that's the standard way to refer to a method already. But even this has
problems in that it puts some limits on reusability. Consider:

module M
def x ; 1 ; end
def y1 ; M#x ; end
def y2 ; M#x ; end
def y3 ; M#x ; end
# etc.
end

Perhaps originally it wasn't intended to be used otherwise, but if we
later wanted to create a variation of M with an altered #x, we'd then
have a problem b/c ordinary code like:

class N
include M


def x ; 2 ; end
end

n = N.new
n.y1 #=> 1
n.y2 #=> 1
n.y3 #=> 1

won't work. To overcome we'd actually have to redefine #y1, #y2, #y3
... and so on. Not good. Of course Ruby has meta-programming techinques
that could be used to get around this, but who wants to dig even
further into complexity? That's why I think a localized namespace would
be preferable, as it is reasonably straightforward and would allow for
both contingencies.

T.

David A. Black

unread,
Apr 11, 2005, 5:21:19 PM4/11/05
to
Hi --

On Tue, 12 Apr 2005, Trans wrote:

>
> Avdi Grimm wrote:
>> Actually, in my mind applying the principle of least astonishment
>> would lead to expecting store and self.store to have identical
>> behaviour. I would expect to have to use something like super.store
>> or A::store in order to specify that I want the superclass version of
>> store.
>
> I have to agree with you. While making a distinction around the use of
> self.x verses x seems reasonable to some degree (after all they are
> written differently), the old ambiguity of x= raises it's ugly head.

They're written differently, but the whole self.x = y thing is just
the price we pay for, in every other situation, being allowed to drop
'self' as the receiver. It keeps things simple and clean, overall
(and it's really not *that* ugly; it's just a receiver :-) So I
wouldn't want to look at that as a rationale for overloading it, which
would make it less simple.

> .... and so on. Not good.

But that's the whole purpose of the thing (whether it's M#x or self.x
or whatever) -- to constrain the nested method call (the call to #x
inside M#y1 etc.) and protect it from the redefinition of #x. I'm not
convinced of the merits of it (I continue to tend to think that anyone
subclassing a class should know the names of that class's methods, and
not accidentally override them), but the idea is specifically to
provide that protection.

Trans

unread,
Apr 12, 2005, 12:19:26 AM4/12/05
to
Hello--

David A. Black wrote:
> On Tue, 12 Apr 2005, Trans wrote:
> They're written differently, but the whole self.x = y thing is just
> the price we pay for, in every other situation, being allowed to drop
> 'self' as the receiver. It keeps things simple and clean, overall
> (and it's really not *that* ugly; it's just a receiver :-) So I
> wouldn't want to look at that as a rationale for overloading it,
which
> would make it less simple.

I don't find the look of it at all ugly, only the asymmetry of that
particular case. But I understand why it must be so.

Also I point out the behavior of calling a private method using self as
the specified reciever: an error. So there is some precedence for
certain distinctions here. But I certainly agree with you, I do not
think it would not be wise to overload it in the manner originally
suggested.

> But that's the whole purpose of the thing (whether it's M#x or self.x
> or whatever) -- to constrain the nested method call (the call to #x
> inside M#y1 etc.) and protect it from the redefinition of #x. I'm
not
> convinced of the merits of it (I continue to tend to think that
anyone
> subclassing a class should know the names of that class's methods,
and
> not accidentally override them), but the idea is specifically to
> provide that protection.

That's only one use case actually. Another is fine-grain control of
inheritance --one can direct methods directly to specific parents. But
I agree with your hesitation for the reason of its nonoopiness (funny
word ;) but that's the trade off. I offered the concept of locals to
gain a middle ground in that trade --not quite as powerful, but
maintains some reusability (a very useful reusability for AOP, I might
add).

Hmmm... now that I think about it more in this light it could also be
interesting to actually define methods in this direct notation as well,
and this might lessen the shortcomings.

class C
def x
"C"
end
end

C.new.x #=> C

def C#x
"CX"
end

C.new.x #=> CX

T.

Trans

unread,
Apr 12, 2005, 12:30:18 AM4/12/05
to
Silly me. I never read the orignal material. I just went back and did
so and now see that the local concept I brought up is really exactly
the kind of solution the author is looking for --at least according to
the stated problem.

The idea of directed method calls (i.e. C#x) is really a separate idea
--albeit related.

Interesting...
T.

Mathieu Bouchard

unread,
Apr 17, 2005, 12:03:20 PM4/17/05
to
0 new messages