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.
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.
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.
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
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:
David Garamond <lists@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.
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.
http://pub.cozmixng.org/~the-rwiki/rw-cgi.rb?cmd=view;name=Ruby2.0MethodSearchRuleEnglish
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.
I want neither util() nor self.util() to call C's util directly, and if either change passes, then I *will* reconsider my five-year relationship with Ruby. I can't even begin to imagine the amount of code that this change would break anyway, so I can't imagine Matz making that change either.
,-o---------o---------o---------o-. ,----. |
> The Diagram is the Program (TM) | | ,-o----------------------------o-.
`-o-----------------------------o-' | | Mathieu Bouchard (Montréal QC) |
···
On Sat, 9 Apr 2005, David Garamond wrote:
> >---' | http://artengine.ca/matju |
> > `-o------------------------------'
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
···
On 2005-04-09, David A. Black <dblack@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
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
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.
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
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...
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.
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.
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 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.
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
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.
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).
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.
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.
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.
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?
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.
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).
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.
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.)
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.
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.
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.