Brian said:
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