Inconsistent value of uninitialized variable

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

Hi,

···

In message “Inconsistent value of uninitialized variable” on 03/12/29, Gavin Sinclair gsinclair@soyabean.com.au writes:

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.

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

<:((><

···

On Dec 28, 2003, at 09:04, Gavin Sinclair wrote:

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.

[snip]

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 :slight_smile:

regards,
andrew

···

On Mon, 29 Dec 2003 00:04:19 +0900, Gavin Sinclair gsinclair@soyabean.com.au wrote:

Gavin Sinclair gsinclair@soyabean.com.au writes:

[…]
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

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

···

On Monday, December 29, 2003, 4:29:45 AM, Nathaniel wrote:

On Dec 28, 2003, at 09:04, Gavin Sinclair wrote:

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

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

···

Nathaniel Talbott nathaniel@talbott.ws 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 suppose you could require a prior assignment to x in this case, but
that starts to smell like having to declare variables…

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

Nathaniel

<:((><

···

On Dec 28, 2003, at 23:11, Martin DeMello wrote:

Nathaniel Talbott nathaniel@talbott.ws 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 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

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

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

y = 0; z = proc{ x = proc{ y+= 1; x.call unless y == 100 }; x.call }
=> #Proc:0x401af0f0@:3(irb)
z.call
=> nil
y
=> 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

:wink:

···

On Mon, Dec 29, 2003 at 02:34:40PM +0900, Nathaniel Talbott wrote:

On Dec 28, 2003, at 23:11, Martin DeMello wrote:

Nathaniel Talbott nathaniel@talbott.ws wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
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

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

“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

···

Nathaniel Talbott nathaniel@talbott.ws wrote:

On Dec 28, 2003, at 23:11, Martin DeMello wrote:

Nathaniel Talbott nathaniel@talbott.ws wrote: