Aliased setter methods behave differently than other methods?

J

Jim Cain

Here's another question... I am aliasing and redefining certain methods,
determined at runtime. Normal methods work fine, but methods ending in
'=' are not behaving the same. Here's an example:

module Mymodule
def Mymodule.append_features(klass)
super(klass)
klass.module_eval do
def self.enalias(s)
alias_method(('old_' + s).intern, s.intern)
module_eval <<-EOF
def #{s}(arg)
puts 'hola ' + arg
old_#{s}(arg)
end
EOF
end
end
end
end

class Myclass
def hello(s)
puts 'hello ' + s
end
include Mymodule
end

class MyclassQ
def hello=(s)
puts 'hello ' + s
end
include Mymodule
end

c = Myclass.new
c.hello('1')
Myclass.enalias('hello')
c.hello('2')
c.old_hello('3')
puts '-----'
q = MyclassQ.new
q.hello=('1')
MyclassQ.enalias('hello=')
q.hello=('2')
q.old_hello=('3')

This outputs the following:

hello 1
hola 2
hello 2
hello 3
-----
hello 1
hola 2
hello 3

Notice that, in the class where the method is "hello=" rather than
"hello", the call to the old method fails somehow. Its output is skipped.

Am I missing something obvious here? Are the setters intended to act
differently somehow? BTW I get this output on both 1.6.8 and 1.8.
 
N

nobu.nokada

Hi,

At Fri, 18 Jul 2003 14:10:24 +0900,
Jim said:
Notice that, in the class where the method is "hello=" rather than
"hello", the call to the old method fails somehow. Its output is skipped.

enalias for hello= will be excuted as bellow:

alias_method(('old_hello=').intern, 'hello='.intern)
module_eval <<-EOF
def hello=(arg)
puts 'hola ' + arg
old_hello=(arg) # just local variable assignment.
end
EOF
 
J

Jim Cain

Hi,

At Fri, 18 Jul 2003 14:10:24 +0900,



enalias for hello= will be excuted as bellow:

alias_method(('old_hello=').intern, 'hello='.intern)
module_eval <<-EOF
def hello=(arg)
puts 'hola ' + arg
old_hello=(arg) # just local variable assignment.
end
EOF

Of course! Duh. I stared and stared at that one and never saw it from
Ruby's point of view. Now I just have to figure out how to make it look
like a method call.
 
M

Mauricio Fernández

send("old_#{whatever}", arg)

That's a lot of work :)

self.old_hello=(arg)

that is,
self.old_#{s}(arg)

--
_ _
| |__ __ _| |_ ___ _ __ ___ __ _ _ __
| '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | |_\__ \ | | | | | (_| | | | |
|_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

<Tazman> damn my office is cold.
<Tazman> need a hot secretary to warm it up.
-- Seen on #Linux
 
G

Gawnsoft

Of course! Duh. I stared and stared at that one and never saw it from
Ruby's point of view. Now I just have to figure out how to make it look
like a method call.


Errmm, not obvious to me (a newbie). What's the significance of the =
suffix in amethod name that makes it behave differently

?



Cheers,
Euan
Gawnsoft: http://www.gawnsoft.co.sr
Symbian/Epoc wiki: http://html.dnsalias.net:1122
Smalltalk links (harvested from comp.lang.smalltalk) http://html.dnsalias.net/gawnsoft/smalltalk
 
B

Brian Candler

Errmm, not obvious to me (a newbie). What's the significance of the =
suffix in amethod name that makes it behave differently

foo = x

is always interpreted as an assignment to local variable 'foo'; and from
that point onwards in that method, 'foo' by itself is treated as a local
variable rather than a method. So, a local variable assignment takes
precedence over any method with the same name which might exist. Hence you
cannot call a method 'foo=' with the above syntax. You can however specify a
receiver (self.foo=) or use 'send', in which case it is unambiguously a
method call.

Ought to be documented here, but doesn't appear to be :)
http://www.rubygarden.org/ruby?ThingsNewcomersShouldKnow

Regards,

Brian.
 
J

Jim Cain

Okay, this works fine now for setters:

module_eval <<-EOF
def #{s}(arg)
puts 'hola ' + arg
self.old_#{s}(arg)
end
EOF

But what about the generic case when you don't know how many arguments a
method takes, and you don't really want to know:

module_eval <<-EOF
def #{s}(*arg)
puts 'hola ' + arg
self.old_#{s}(*arg) # syntax error
end
EOF

I get a syntax error on the method call, but only for setters. Is a
method with a name like "somemethod=" required to take exactly one argument?
 
B

Brian Candler

But what about the generic case when you don't know how many arguments a
method takes, and you don't really want to know:

module_eval <<-EOF
def #{s}(*arg)
puts 'hola ' + arg
self.old_#{s}(*arg) # syntax error
end
EOF

I get a syntax error on the method call, but only for setters. Is a
method with a name like "somemethod=" required to take exactly one argument?

irb(main):001:0> class Foo
irb(main):002:1> def x=(a,b)
irb(main):003:2> puts a,b
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> a = Foo.new
=> #<Foo:0x81ae97c>
irb(main):007:0> a.x=(1,2)
SyntaxError: compile error

But:

irb(main):008:0> a.send:)x=,1,2)
1
2
=> nil

Regards,

Brian.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top