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 Schmidt

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!

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

···

On 5/26/07, Henrik Schmidt <no.spam@nspmaxyz.abc> wrote:

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

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, 9:35 am, Henrik Schmidt <no.s...@nspmaxyz.abc> wrote:

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?

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).

···

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

Best regards,
  Henrik Schmidt

Hakusa@gmail.com 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.

Trans wrote:

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?

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.

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

···

On May 26, 9:35 am, Henrik Schmidt <no.s...@nspmaxyz.abc> 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 don't really know when it would be useful, but who knows. What if
someday I find that it is?

Henrik Schmidt 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.

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.

···

Hakusa@gmail.com wrote:

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.

···

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

Hakusa@gmail.com 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.

Hakusa@gmail.com 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.

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.

Brian Candler 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.

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 "$"

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.

(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.

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 Schmidt

···

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

Hakusa@gmail.com wrote:

Henrik Schmidt 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

Hakusa@gmail.com 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?

Hi --

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.

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 Sun, 27 May 2007, Henrik Schmidt wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

>(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 "$"

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.

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.

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.

···

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

class X
    def foo; "blah"; end

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

T.

···

On May 26, 1:05 pm, Henrik Schmidt <no.s...@nspmaxyz.abc> wrote:

Hak...@gmail.com 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?