Inconsistent value of uninitialized variable

G

Gavin Sinclair

The following statement, free of all context, generates an error:

x # NameError: undefined local variable or method `x' ...

So does this one:

x = y # NameError: undefined local variable or method `y' ...

However, this one does not (again, free of all context):

x = x
x # nil

This, to me, is inconsistent and undesirable behaviour. I would
prefer this:

x = x # NameError: undefined local variable or method `x' ...

I haven't given it much thought, but the existing behaviour cost me 15
minutes debugging, and I:
* don't see a benefit of the existing behaviour;
* do see a benefit (consistency) of changing the behaviour.

Any comments?

Gavin
 
Y

Yukihiro Matsumoto

Hi,

In message "Inconsistent value of uninitialized variable"

|However, this one does not (again, free of all context):
|
| x = x
| x # nil
|
|This, to me, is inconsistent and undesirable behaviour. I would
|prefer this:
|
| x = x # NameError: undefined local variable or method `x' ...
|
|I haven't given it much thought, but the existing behaviour cost me 15
|minutes debugging, and I:
| * don't see a benefit of the existing behaviour;
| * do see a benefit (consistency) of changing the behaviour.
|
|Any comments?

It's just application of the simple rule "local variables are defined
when they first appear in the left side of assignment", and was much
easier to implement.

I wouldn't disagree with you (but not really motivated enough to fix
by myself).

matz.
 
N

Nathaniel Talbott

This, to me, is inconsistent and undesirable behaviour. I would
prefer this:

x = x # NameError: undefined local variable or method `x' ...

I haven't given it much thought, but the existing behaviour cost me 15
minutes debugging, and I:
* don't see a benefit of the existing behaviour;
* do see a benefit (consistency) of changing the behaviour.

Isn't it this behavior that makes it possible to define a recursive
block?

y = 0
x = proc{y += 1; x.call unless(y == 100); y}
p x.call

I suppose you could require a prior assignment to x in this case, but
that starts to smell like having to declare variables...

Just my $0.02,


Nathaniel

<:((><
 
A

Andrew Johnson

On Mon, 29 Dec 2003 00:04:19 +0900, Gavin Sinclair
However, this one does not (again, free of all context):

x = x
x # nil

This, to me, is inconsistent and undesirable behaviour. I would
prefer this:

x = x # NameError: undefined local variable or method `x' ...

I haven't given it much thought, but the existing behaviour cost me 15
minutes debugging, and I:
* don't see a benefit of the existing behaviour;
* do see a benefit (consistency) of changing the behaviour.

Any comments?


Just recently there was a discussion on using procs that referenced
methods not yet defined:

even = proc{|x| x == 0 ? true : odd[x-1]}
odd = proc{|x| x == 0 ? false : even[x-1]}
p even[5]

and we get an error because 'odd' is undefined when 'even' was defined.
One way around this is to simply set 'odd' to nil first:

odd = nil
even = proc{|x| x == 0 ? true : odd[x-1]}
odd = proc{|x| x == 0 ? false : even[x-1]}
p even[5]

But, as a result of current behavior, the extra nil assignment can be
avoided via:

even, odd = proc {|x| x == 0 ? true : odd[x-1]},
proc {|x| x == 0 ? false : even[x-1]}
p even[5]

I'm sure opinions will vary greatly on whether this is a benefit :)

regards,
andrew
 
J

Johan Holmberg

Gavin Sinclair said:
[...]
This, to me, is inconsistent and undesirable behaviour. I would
prefer this:

x = x # NameError: undefined local variable or method `x' ...

I haven't given it much thought, but the existing behaviour cost me 15
minutes debugging, and I:
* don't see a benefit of the existing behaviour;
* do see a benefit (consistency) of changing the behaviour.

I had a similar problem a while ago that also took time to debug.
I had code looking something like this:

x_misspelled = 33
...
x = 100 if x == -1

Because of the rule Matz referred to in his reply to your mail (that
"local variables are defined when they first appear in the left side
of assignment"), this code doesn't give an error. If I had written

x_misspelled = 33
...
if x == -1
x = 100
end

I would have got a NameError saying "undefined local variable
or method...".

I think these two code fragments does the same thing "logically", and
that it would have been nice if the if-modifier-form also had caught
my error.

/Johan Holmberg
 
G

Gavin Sinclair

On Dec 28, 2003, at 09:04, Gavin Sinclair wrote:
Isn't it this behavior that makes it possible to define a recursive
block?
y = 0
x = proc{y += 1; x.call unless(y == 100); y}
p x.call

I don't believe so, because the 'x' in question above is not being
assigned; 'x.call' is semantically equivalent to 'x' (an rvalue), not
'x = something' (an lvalue).

What makes the above code possible is that 'x' in 'x.call' is not
evaluated until it is actually run; there's no compiler to please.

Gavin
 
M

Martin DeMello

Nathaniel Talbott said:
Isn't it this behavior that makes it possible to define a recursive
block?

y = 0
x = proc{y += 1; x.call unless(y == 100); y}
p x.call

I suppose you could require a prior assignment to x in this case, but
that starts to smell like having to declare variables...

This is not a proper recursive block - for instance

y = 0
x = proc{y += 1; x.call unless(y == 100); y}
z = x
x = nil
z.call

martin
 
N

Nathaniel Talbott

This is not a proper recursive block - for instance

y = 0
x = proc{y += 1; x.call unless(y == 100); y}
z = x
x = nil
z.call

"Not proper" might be strong language, but yes, it could definitely be
broken. Do you have a better construct for a recursive block?


Nathaniel

<:((><
 
M

Mauricio Fernández

"Not proper" might be strong language, but yes, it could definitely be
broken. Do you have a better construct for a recursive block?
=> 100

With the new block local rules,
y = 0; z = proc{|*z| z = proc{y += 1; z.call unless y == 100}; z.call }
a = z
z = nil
a.call

would work too (you'd get a warning IIRC, though).

If you're "evil" enough you might like the following too:

y = 0

proc {|l| proc{|f| f.call(f)}.call(proc{|f|
l.call(proc{|*x| f.call(f).call(x)})})
}.call(proc {|r| proc{y += 1; r.call unless y == 100}}).call

;)

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

I tried the clone syscall on me, but it didn't work.
-- Mike Neuffer trying to fix a serious time problem
 
M

Martin DeMello

Nathaniel Talbott said:
"Not proper" might be strong language, but yes, it could definitely be

Sorry. Actually, you're right - this'll cover nearly every case in which
you'd want the construct, but relying on a variable name makes me
twitchy.
broken. Do you have a better construct for a recursive block?

No, I remember fighting over it once, but I didn't get anywhere. I'd
like to see some equivalent to letrec in 2.0, personally.

martin
 

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,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top