Local vars clobbered by un-run code


#1

Err…

irb(main):001:0> def x; 1; end
=> nil
irb(main):002:0> p x
1
=> nil
irb(main):003:0> if false
irb(main):004:1> x = x() + 1
irb(main):005:1> end
=> nil
irb(main):006:0> x
=> nil

Don’t tell me, it’s some quirk of the way Ruby works. Sure looks like
a bug though. Just in case:

ruby 1.8.4 (2005-12-24) [i486-linux]

Hmm… I just got a dejavu. Maybe I came across this before.

T.


#2

Hi,

It’s not a bug. Assignments makes identifiers local variables,
statically.

          matz.

In message “Re: local vars clobbered by un-run code”
on Tue, 19 Jun 2007 11:21:03 +0900, Trans removed_email_address@domain.invalid
writes:
|
|Err…
|
| irb(main):001:0> def x; 1; end
| => nil
| irb(main):002:0> p x
| 1
| => nil
| irb(main):003:0> if false
| irb(main):004:1> x = x() + 1
| irb(main):005:1> end
| => nil
| irb(main):006:0> x
| => nil
|
|Don’t tell me, it’s some quirk of the way Ruby works. Sure looks like
|a bug though. Just in case:
|
| ruby 1.8.4 (2005-12-24) [i486-linux]
|
|Hmm… I just got a dejavu. Maybe I came across this before.
|
|T.


#3

On Jun 18, 10:35 pm, Yukihiro M. removed_email_address@domain.invalid wrote:

Hi,

It’s not a bug. Assignments makes identifiers local variables,
statically.

                                                    matz.

This must be the matz-bot. The answer came instantaneously and, deja-
vu again, I think it’s same one I got before :wink:

Thanks matz,
T.


#4

On 19 jun, 07:48, “Robert D.” removed_email_address@domain.invalid wrote:

=> nil

Surely the statements inside if are not executed.

No, but they are parsed. And identifiers are made local variables at
parse time, not at execution time. So if you have an assignment
anywhere, even in a place that will never actually execute, the
identifier used in the assignment will be considered a local variable
by the interpreter.

Christophe.


#5

On 6/19/07, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

No, but they are parsed. And identifiers are made local variables at
parse time, not at execution time. So if you have an assignment
anywhere, even in a place that will never actually execute, the
identifier used in the assignment will be considered a local variable
by the interpreter.

Christophe.

I guess this can be concluded by what is happening, but is this any
reason to accept this behavior? I honestly do not feel so!

Cheers
Robert


#6

On 6/19/07, Trans removed_email_address@domain.invalid wrote:

This must be the matz-bot. The answer came instantaneously and, deja-
vu again, I think it’s same one I got before :wink:
Let us see?

Which assignment Matz?

irb(main):001:0> def x;1 end
=> nil
irb(main):002:0> if false then
irb(main):003:1* def x; 2 end
irb(main):004:1> end
=> nil
irb(main):005:0> x
=> 1
irb(main):006:0> def y; 1 end
=> nil
irb(main):007:0> if false
irb(main):008:1> undef y
irb(main):009:1> end
=> nil
irb(main):010:0> y
=> 1

Surely the statements inside if are not executed.

Cheers
Robert


#7

On Jun 19, 4:30 am, “Robert D.” removed_email_address@domain.invalid wrote:

Christophe.

I guess this can be concluded by what is happening, but is this any
reason to accept this behavior? I honestly do not feel so!

I do not feel so either. But, I’ve also learned that Ruby just has
some quirks. Matz wouldn’t had done it this way unless there was a
very real need to do so. Now, that’s not to say he might not have
missed a better solution, so it’s still worth discussing if anyone has
one.

T.


#8

Trans wrote:

Don’t tell me, it’s some quirk of the way Ruby works. Sure looks like
a bug though. Just in case:

ruby 1.8.4 (2005-12-24) [i486-linux]

Hmm… I just got a dejavu. Maybe I came across this before.

T.

T all you showed is that sometimes the programmer must be responsible
for knowing whether he wants to reference a function or a variable.

Consider:

def x
1
end

p x #recognize function call without parens

if false
x = x() + 1 #variable x is created when code parsed
end

p x #reference the variable x which is nil because no assignment was
made
p x() #if the above were the function, how would you reference the
variable?

Result:

1
nil
1

Ian


#9

On Jun 19, 4:02 pm, Ian W. removed_email_address@domain.invalid wrote:

T all you showed is that sometimes the programmer must be responsible
for knowing whether he wants to reference a function or a variable.

One of things I always liked about Ruby is the fact the local vars and
methods are, in a certain sens of the word, polymorphic. Where a
method is being called, I can easily change it to be a variable. I
don’t have to go thru the code and remove ()s or vice versa.

def chip
“%s chip”
end

def good
chip = “forget the %s chip”
puts chip % “good”
end

So if you can do that, it would seem reasonable that one could do so
conditionally as well. I find it odd that x is being setup as a local
var before ever being assigned as such. That’s quite declarative for a
language that tends to shuns such things.

T.


#10

On Jun 19, 4:27 pm, “Robert D.” removed_email_address@domain.invalid wrote:

Maybe, probably I am wrong, but I feel that when it comes to these
subtle things Ruby is lacking consistency.

There just seems no reason for some behavior and your example above is
a classical example. You ask yourself why and you cannot find an
answer.

And worst of all, you have to remember!!

Still a great, great language of course.

That is true. Ruby does have some rough edges. Though I chalk much of
it up to the fact that convenience and flexibility often comes with a
price of a few quirks.

T.


#11

“Robert D.” removed_email_address@domain.invalid writes:

I guess this can be concluded by what is happening, but is this any
reason to accept this behavior? I honestly do not feel so!

On the other hand, I find the idea that the scoping and binding of
variables could change based on the particular code path followed at
run time a horribly non-intuitive concept, since I think of “variable
scope” as something as static as the code itself - that is, you should
only be able to screw with variable scoping by strange
meta-programming tricks.


#12

On 6/19/07, Ian W. removed_email_address@domain.invalid wrote:

Trans wrote:
Tom it just strikes me, your thread and mine about Singleton classes
not being in ancestors and small other things I always see the same
pattern. Rick’s blog entry is another example, always the same
pattern, it is the pattern of imperfection which is the only thing
that slightly bothers me in Ruby:

Consistency.

Maybe, probably I am wrong, but I feel that when it comes to these
subtle things Ruby is lacking consistency.

There just seems no reason for some behavior and your example above is
a classical example. You ask yourself why and you cannot find an
answer.

And worst of all, you have to remember!!

Still a great, great language of course.

Robert


#13

On 2007-06-20 07:37:14 +0900 (Wed, Jun), Daniel M. wrote:

On the other hand, I find the idea that the scoping and binding of
variables could change based on the particular code path followed at
run time a horribly non-intuitive concept, since I think of “variable
scope” as something as static as the code itself - that is, you should
only be able to screw with variable scoping by strange
meta-programming tricks.

Maybe I don’t understand something, but the decision whether something
is a variable or is a method call is based not on the code executed
(which is hard to predict when reading the source) but on the code
parsed, which is pretty static.

def this_method( x )
p y # This ‘y’ will always be a method call.
# (even if you call this_method again)
if x
y = 1 # because of this line in the source code…
end
p y # …this ‘y’ will always be a variable.
end # …independent on the value of x

So, I would (IMHO) assume, that this is not bad-black-magic, but
good-and-understandable-white-magic aspect of ruby.

The confision may emerge when the block of code has many lines, hard to
grasp in one eye shot, but I have been taught that if you write a
function that is longer than half of your editor window you should
extract part of it into another function.
With short blocks it is harder to mistake a method for a variable.

P.S.:
If someone still does not like this magic behaviour, assume that it
saves you from writing:

def this_method( x )
p y
if x
#pragma set_as_variable(y) /* and if you forgot, you will get
parse-error */
y = 1
end
p y
end

:wink: