Inconsistent value of uninitialized variable

Discussion in 'Ruby' started by Gavin Sinclair, Dec 28, 2003.

  1. 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
     
    Gavin Sinclair, Dec 28, 2003
    #1
    1. Advertising

  2. Hi,

    In message "Inconsistent value of uninitialized variable"
    on 03/12/29, Gavin Sinclair <> 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.
     
    Yukihiro Matsumoto, Dec 28, 2003
    #2
    1. Advertising

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

    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

    <:((><
     
    Nathaniel Talbott, Dec 28, 2003
    #3
  4. On Mon, 29 Dec 2003 00:04:19 +0900, Gavin Sinclair
    <> wrote:
    [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 :)

    regards,
    andrew
     
    Andrew Johnson, Dec 28, 2003
    #4
  5. Gavin Sinclair <> 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
     
    Johan Holmberg, Dec 28, 2003
    #5
  6. 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


    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
     
    Gavin Sinclair, Dec 28, 2003
    #6
  7. Nathaniel Talbott <> 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

    martin
     
    Martin DeMello, Dec 29, 2003
    #7
  8. On Dec 28, 2003, at 23:11, Martin DeMello wrote:

    > Nathaniel Talbott <> 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


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


    Nathaniel

    <:((><
     
    Nathaniel Talbott, Dec 29, 2003
    #8
  9. 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 <> 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

    >
    > "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@(irb):3>
    >> 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

    ;)

    --
    _ _
    | |__ __ _| |_ ___ _ __ ___ __ _ _ __
    | '_ \ / _` | __/ __| '_ ` _ \ / _` | '_ \
    | |_) | (_| | |_\__ \ | | | | | (_| | | | |
    |_.__/ \__,_|\__|___/_| |_| |_|\__,_|_| |_|
    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
     
    Mauricio Fernández, Dec 29, 2003
    #9
  10. Nathaniel Talbott <> wrote:
    > On Dec 28, 2003, at 23:11, Martin DeMello wrote:
    >
    > > Nathaniel Talbott <> 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

    >
    > "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
     
    Martin DeMello, Dec 29, 2003
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Oliver Wong
    Replies:
    11
    Views:
    925
    Hendrik Maryns
    Apr 19, 2006
  2. Michael Hohn

    inconsistent value from __builtins__

    Michael Hohn, Oct 1, 2004, in forum: Python
    Replies:
    1
    Views:
    282
    Alex Martelli
    Oct 1, 2004
  3. Philipp Klaus Krause

    Value of uninitialized variable

    Philipp Klaus Krause, Jan 19, 2010, in forum: C Programming
    Replies:
    27
    Views:
    2,446
    Ben Bacarisse
    Jan 23, 2010
  4. Ilias Lazaridis
    Replies:
    17
    Views:
    620
    Ilias Lazaridis
    Jun 20, 2011
  5. Alextophi
    Replies:
    2
    Views:
    149
    Alextophi
    Sep 14, 2005
Loading...

Share This Page