Local variables vs. methods

Hi there,

I’ve been playing around with Ruby for a while, but there’s still one
particular feature of the language that doesn’t make sense to me. If you
write a class containing a method and a class with the same name, the
interpreter will pick the variable over the method, unless you
specifically tells it not to. For example,

class Foo

def output
puts foo # “foo”
foo = 42
puts foo # 42
puts self.foo # “foo”
puts foo() # “foo”
end

def foo
“foo”
end

end

Foo.new.output

As seen above, there are several ways of getting around this, but this
is the question: Why is this behaviour useful? As I see it, it’s bad
practice to give a method and a local variable the same name. At least I
can’t think of an example where it would make sense. Why not simply
disallow this or at least have the interpreter issue a warning?

Best regards,
Henrik S.

If a language stops you from doing something just because it’s bad
practice, then the language is treating you like an idiot. What if I
wanted to override a function for a little while? I could assign it a
new value and use the same methods of a different class!

On 5/26/07, Henrik S. [email protected] wrote:

end

end

Foo.new.output

C++ does the same thing, you know. It’s not mysterious if you understand
how
the language’s scoping rules work.

[email protected] wrote:

If a language stops you from doing something just because it’s bad
practice, then the language is treating you like an idiot.

Fine, so don’t stop be. Warn me that I’m doing something which is
probably a programmer error 99% of the time. Ruby stops me from all
sorts of things I can do in Perl. I think that’s a good thing, since I’m
a horrible Perl programmer :slight_smile:

What if I
wanted to override a function for a little while? I could assign it a
new value and use the same methods of a different class!

Then you’ll just override it. My question is, why would you want to
override a method with a variable? I have no problem with overloading a
method with another method, and neither should the interpreter.

Henrik S. wrote:

wanted to override a function for a little while? I could assign it a
new value and use the same methods of a different class!

Then you’ll just override it. My question is, why would you want to
override a method with a variable? I have no problem with overloading a
method with another method, and neither should the interpreter.

In fact, now that I think about it, how would you override a method from
one class with a variable in another class making use of this feature?

Last year I asked a question also pertaining to variable/method
ambiguity. At the time I thought one solution might be to force
parentheses on all methods. I got some very good answers why this was a
bad idea. The best answer was, IMHO, that it would make the private and
protected methods look strange and unintuitive. The implication of that
was of course, that you could create methods like private and protected
and have them behave as keywords or even overload these methods and have
them behave differently. I wasn’t aware of that of the time, and I think
that’s pretty cool.

Basically, I’m looking for the same thing here. What possible use can
there be for this feature? I don’t get it.

What if I
wanted to override a function for a little while? I could assign it a
new value and use the same methods of a different class!

Then you’ll just override it. My question is, why would you want to
override a method with a variable? I have no problem with overloading a
method with another method, and neither should the interpreter.

What if instead of printing bar’s output with puts bar, bar was a
local variable so it printed an error message alerting the user that
something wrong has happened.

I don’t really know when it would be useful, but who knows. What if
someday I find that it is?

Basically, I’m looking for the same thing here. What possible use can
there be for this feature? I don’t get it.

Thought of something:
I still don’t really know how to use a proc or anything like that, but
it seems to me …

proc = Proc.new # How you initialize a proc makes me think that a proc
is just another type of a variable.

So you could overload your method with a variable so that a proc which
does a different thing is called. If you can see why overloading with
a method could be good, you can see why this could be good.

But note that I’m not all that experienced either, so I could be
entirely wrong. But I still think that someday, it just might be
helpful.

[email protected] wrote:

What if I
wanted to override a function for a little while? I could assign it a
new value and use the same methods of a different class!
Then you’ll just override it. My question is, why would you want to
override a method with a variable? I have no problem with overloading a
method with another method, and neither should the interpreter.

What if instead of printing bar’s output with puts bar, bar was a
local variable so it printed an error message alerting the user that
something wrong has happened.

I think a nicer way of doing this would be to overload bar with a method
that throws an exception.

I don’t really know when it would be useful, but who knows. What if
someday I find that it is?

If you can do the same thing with a method I don’t see the problem.
Also, it would eliminate (or at least warn) when you do this:

def foo
42
end

puts foo # -> 42
foo = 24 if false;
puts foo # -> nil

I would like to be warned in this situation, as it’s fairly likely I’m
doing something I didn’t intend to do.

[email protected] wrote:

Basically, I’m looking for the same thing here. What possible use can
there be for this feature? I don’t get it.

Thought of something:
I still don’t really know how to use a proc or anything like that, but
it seems to me …

proc = Proc.new # How you initialize a proc makes me think that a proc
is just another type of a variable.

It is.

So you could overload your method with a variable so that a proc which
does a different thing is called. If you can see why overloading with
a method could be good, you can see why this could be good.

Well, if you would like proc to do something different then just assign
a different Proc to it. Also, I don’t think you can overload proc with a
method. The variable always wins.

But note that I’m not all that experienced either, so I could be
entirely wrong. But I still think that someday, it just might be
helpful.

I can’t think of any way, contrived or otherwise, that would make this
helpful, but I’m fairly inexperienced myself. Let’s say I accept your
argument. Why not issue a warning?

On May 26, 9:35 am, Henrik S. [email protected] wrote:

def output

end

Foo.new.output

As seen above, there are several ways of getting around this, but this
is the question: Why is this behaviour useful? As I see it, it’s bad
practice to give a method and a local variable the same name. At least I
can’t think of an example where it would make sense. Why not simply
disallow this or at least have the interpreter issue a warning?

Perhaps we could ask about this from the opposite perspective. Would
it not be useful to define local methods --in method scope?

def foo
def bar; 10; end
bar
end

In effect then, a method is nothing more than a lazy variable having
it’s own specific rules of scope. There’s really no good reason to
restrict name clash.

T.

On May 26, 1:05 pm, Henrik S. [email protected] wrote:

method. The variable always wins.

But note that I’m not all that experienced either, so I could be
entirely wrong. But I still think that someday, it just might be
helpful.

I can’t think of any way, contrived or otherwise, that would make this
helpful, but I’m fairly inexperienced myself. Let’s say I accept your
argument. Why not issue a warning?

class X
def foo; “blah”; end

def bar
  if something_or_another
    foo = "big blah"
  end
  puts foo
end

end

T.

On Sun, May 27, 2007 at 01:00:03AM +0900, Henrik S. wrote:

wanted to override a function for a little while? I could assign it a
new value and use the same methods of a different class!

Then you’ll just override it. My question is, why would you want to
override a method with a variable? I have no problem with overloading a
method with another method, and neither should the interpreter.

The trouble is:

(1) All objects are descendants of Object, which in turn mixes in
Kernel.
Many other objects mix in Enumerable, Comparable and other modules.

This means that a typical object has roughly a googol different methods
already present, and it’s very easy to pick a local variable name which
happens to collide with one. Silently ignoring this “just works”. Giving
an
error would be very annoying; instead of “id = 9” I’d have to change it
to
“my_id = 9” or somesuch. In the end I’d prefix all local variables with
my_… which would be worse than using something perlish like “$”

(2) From a very practical perspective, it’s extremely difficult for Ruby
to
generate these warnings.

The problem is: Ruby is a completely dynamic language, and at parse time
you
have no idea what methods an object has. The decision as to ‘local
variable’
or ‘method’ is made statically, based on inspection of the code
before it’s executed, which means before any classes and methods have
been
created.

To perform the check you’re asking for, Ruby would have to add extra
run-time code after every local variable access to perform a method
search
just to check if a method with the same name exists. Example:

10000.times do
x = flurble()
y = y + x
end

Each time round the loop, the call to flurble() may have ended up
defining a
method called ‘x’ in the current object. So every time round the loop,
you’d
have to check, at the point where ‘x’ was read and/or assigned, that
there
was currently no method called ‘x’ (or ‘x=’) in the object.

Regards,

Brian.

Trans wrote:

class Foo
“foo”
disallow this or at least have the interpreter issue a warning?
it’s own specific rules of scope. There’s really no good reason to
restrict name clash.

T.

I didn’t know you could do that. That’s kinda horrible :slight_smile:

Brian C. wrote:

wanted to override a function for a little while? I could assign it a

This means that a typical object has roughly a googol different methods
already present, and it’s very easy to pick a local variable name which
happens to collide with one. Silently ignoring this “just works”. Giving an
error would be very annoying; instead of “id = 9” I’d have to change it to
“my_id = 9” or somesuch. In the end I’d prefix all local variables with
my_… which would be worse than using something perlish like “$”

Hmmm, I didn’t think of that. Local variable/method ambiguity is only a
problem within the class. If you mix in something, you need to be aware
of which methods these mixins have. Otherwise you, or anyone who uses
your class might get unexpected results. If I decide to give all my
classes an id method, someone calling the my_class.id will probably not
get the result he wanted. My point is, that you need to be aware that
you’re actually overloading a mixed in or inherited method anyway.
Normally I would think that’s a reasonable requirement, and anyone can
look through Kernel and Object to get an idea of which method-names are
dangerous. Of course, it might have been a good idea to give these
methods less generic names. I’m not sure why they deprecated the id
method, but I guess it might have something to do with this. Can anyone
clue me in?

Anyway, it could be partially solved by only issuing a warning if your
local variable is actually shadowing a local method, but I definitely
see your point.

To perform the check you’re asking for, Ruby would have to add extra
have to check, at the point where ‘x’ was read and/or assigned, that there
was currently no method called ‘x’ (or ‘x=’) in the object.

I found this googling
(http://talklikeaduck.denhaven2.com/xml/rss20/article/256/feed.xml):

class Point
attr_accessor :x, :y

def initialize(init_x,init_y)
   x, y = init_x, init_y
end

end

p Point.new(10,10).x => nil

That’s a fair mistake. The compiler doesn’t know about the attr_accessor
so it thinks x and y are local variables. What I don’t understand is,
that even if you put in the appropriate methods instead of relying on
attr_accessor, it still doesn’t work.

Anyway, I still think one could make a sensible warning system to be run
at compile-time that would catch most of the more obvious programmer
errors, but it wouldn’t be perfect. The counter-argument would be that
we’re probably better off leaving it alone so people will fall into the
trap, learn what happens, and stop doing it early on. Then again, a
warning would probably lead them to the path of enlightenment earlier.

I still wouldn’t mind getting a warning, but I didn’t realize all the
implications of trying to fix it, so I guess I can accept that since
there seem to be no way to fix it properly without sigils anyway, it
should be left as it is.

Thanks for the explanation,
Henrik S.

Henrik S. wrote:

Basically, I’m looking for the same thing here. What possible use can
there be for this feature? I don’t get it.

Sometimes I use that “feature” to cache a method’s response. e.g.:
foo = self.foo
#do a bunch of things with foo without having to call the method

But I think the ability to override a method with a local variable is
not so much a feature as a side-effect of the synctatic simplicity of
invoking a method as only “foo” instead of “foo()” or “self.foo”

Like you, I am also a little annoyed by the inconsistence:
foo #variable or method
foo() #method
self.foo #method
foo=1 #variable
self.foo=1 #method
foo=(1) #variable

but I think consistence is a small price to pay for a syntax that
doesn’t get in your way in 99% of cases.

Daniel

On Sun, May 27, 2007 at 06:25:09AM +0900, Henrik S. wrote:

Hmmm, I didn’t think of that. Local variable/method ambiguity is only a
problem within the class. If you mix in something, you need to be aware
of which methods these mixins have. Otherwise you, or anyone who uses
your class might get unexpected results. If I decide to give all my
classes an id method, someone calling the my_class.id will probably not
get the result he wanted.

I disagree. If someone uses your class, then he or she will look at your
rdoc documentation, and see you have an ‘id’ method and, if it’s what
they
want to use, will call it.

Now of course, this hides the system ‘id’ method (which happens to be
deprecated anyway). But you’ll find this done where it’s appropriate,
e.g.
ActiveRecord uses foo.type = bar

However, this has no impact at all on local variables. If a user of your
class decides to write “id = 123”, then this always generates a local
variable, and this can be seen immediately, by inspection of the code
locally, without having to cross-reference to the class definition.

Equally, if you do

class Myclass < Other
def foo

x = 1

end
end

then you don’t have to worry whether class Other has a method called ‘x’
or
not (or if it doesn’t today, that perhaps it might grow one tomorrow).
It’s
unambiguously a local variable called ‘x’ that you’re using.

That’s a fair mistake. The compiler doesn’t know about the attr_accessor
so it thinks x and y are local variables. What I don’t understand is,
that even if you put in the appropriate methods instead of relying on
attr_accessor, it still doesn’t work.

Because of the very simple rule that says “a statement of the form ‘x =
…’
always makes x a local variable from this point until the end of the
current scope”. If you want to call a method called ‘x=’ then you always
need to do self.x=

I sympathise with your concern - a few times I’ve written some code
which
fails unit tests and had to stare at it for a while, before realising
what
I’d done. This is particularly true for ActiveRecord, which has lots of
accessors, and where you might be tempted to write “something = nil”
instead
of “self.something = nil”

However, if you want a warning for the code above, I think a better one
would be “local variable x assigned but not used”. Actually that
shouldn’t
be too hard to add, and I imagine it could indeed catch a few silly
typos.

Regards,

Brian.

Hi –

On Sun, 27 May 2007, Henrik S. wrote:

p Point.new(10,10).x => nil

That’s a fair mistake. The compiler doesn’t know about the attr_accessor so
it thinks x and y are local variables. What I don’t understand is, that even
if you put in the appropriate methods instead of relying on attr_accessor, it
still doesn’t work.

It does work – it assigns init_x and init_y to the local variables x
and y, which is what you’ve asked it to do :slight_smile: If you want to call x=
and y=, you can do:

self.x, self.y = init_x, init_y

or, since this is just a simple accessor:

@x, @y = init_x, init_y

Anyway, I still think one could make a sensible warning system to be run at
compile-time that would catch most of the more obvious programmer errors, but
it wouldn’t be perfect. The counter-argument would be that we’re probably
better off leaving it alone so people will fall into the trap, learn what
happens, and stop doing it early on. Then again, a warning would probably
lead them to the path of enlightenment earlier.

My counterargument is that you’d then have the system fighting itself.
On the one hand, it’s engineered so that there’s a kind of fluidity
between method and local variable names, in certain circumstances; but
on the other hand, you’ve start getting warnings if you avail yourself
of that fluidity.

Even a small test suite should expose problems in this area quickly.
You’d immediately see that your new Point object wasn’t doing what you
expected, and you could track down the problem and fix it. Meanwhile
you’d be able to reap the advantages of the system without being
interrupted by warnings.

David

On Sat, May 26, 2007 at 10:35:03PM +0900, Henrik S. wrote:

As seen above, there are several ways of getting around this, but this
is the question: Why is this behaviour useful? As I see it, it’s bad
practice to give a method and a local variable the same name. At least I
can’t think of an example where it would make sense. Why not simply
disallow this or at least have the interpreter issue a warning?

Just to throw out another reason, that I don’t think has been mentioned
yet, it would be expensive. For the interpreter to issue a warning about
local variables shadowing method names, it would require the interpreter
to do a method lookup on every variable assignment. And it couldn’t
even be at parse time, it would have to be every time. Eg:

class A
def bar
foo = 1 # the interpreter doesn’t yet know that there will be a foo
# method
foo
end

def foo
“foo”
end
end

Therefore, it has to do at least 2 method lookups everytime I call

bar below, one for bar itself, and one to make sure foo isn’t a method

v = A.new
v.bar
v.bar
v.bar

It also can’t cache the need to warn, because I can remove_method :foo,
making the warning incorrect.

Method lookup on every assign would not be a cheap operation. (I know we
don’t usually like to talk about speed here, but this would be really
bad).