Forum: Ruby undefineds and or-equals

Aa082c8b00a50928e5860dcd70bf2368?d=identicon&s=25 tamouse m. (tamouse_m)
on 2013-10-23 18:35
(Received via mailing list)
So, we all know that this works:

    foo ||= nil
    puts "blah" if foo # => nil

but prior to that point, foo has not been defined.

If instead of the or-equals first, one tries:

    puts "blah" if foo

one gets a NameError exception.

What is the actual mechanism in Ruby that allows the first form where
foo has not yet been defined? I know it works, I'm trying to understand
why the first form does not also raise the NameError? Ruby magic? (This
is just idle curiosity, I'm not really sweating over this!)
B7a68e8ba5bb2d4e9730b69a6ae36554?d=identicon&s=25 Corin Schedler (Guest)
on 2013-10-23 19:56
(Received via mailing list)
On 10/23/2013 11:34 AM, Tamara Temple wrote:
>
> one gets a NameError exception.
>
> What is the actual mechanism in Ruby that allows the first form where foo has
not yet been defined? I know it works, I'm trying to understand why the first 
form
does not also raise the NameError? Ruby magic? (This is just idle curiosity, I'm
not really sweating over this!)
>
>

I'm not really sure if I know what you're asking but I can give it a
shot.

The mechanism that allows this particular paradigm in Ruby is the ||=
operator itself. Many have waxed poetic about it [1] but the basic gist
is that ||= acts very similarly to:

  foo || foo = nil

I say "very similarly" because you could try to run the above code and
it would throw a NameError. When the 'shorthand' of that expression
(||=) is encountered the parser executes some Ruby Magic(tm) and creates
the foo variable in a way that doesn't throw an error. The example [1]
uses is helpful here. If you run this:

  x = 1 if 2 == 5
  puts x

Ruby will output 'nil' instead of throwing a NameError. The assignment
(even if it's never directly evaluated) causes the parser to create x in
such a way that it's usable later on. Same thing with ||=.

Does that answer your question? You may be asking something else here.

[1]
http://www.rubyinside.com/what-rubys-double-pipe-o...
Aa082c8b00a50928e5860dcd70bf2368?d=identicon&s=25 tamouse m. (tamouse_m)
on 2013-10-24 08:07
(Received via mailing list)
On Oct 23, 2013, at 12:55 PM, Corin Schedler <corin@dubdromic.com>
wrote:

>>     puts "blah" if foo
>
>
> [1]
http://www.rubyinside.com/what-rubys-double-pipe-o...

I am familiar with that "very similar" thing. It's the Ruby Magic []
thing I more wondering about. The example you gave is also interesting.
This isn't a really serious enquiry, I was just wondering how Ruby makes
the determination about what's defined when and how in these situations.
On the occasions where I see that NameError thrown, it's pretty obvious
what I (haven't) done.
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2013-10-24 12:09
(Received via mailing list)
On Thu, Oct 24, 2013 at 8:06 AM, Tamara Temple <tamouse.lists@gmail.com>
wrote:
> I am familiar with that "very similar" thing. It's the Ruby Magic [] thing I
more wondering about. The example you gave is also interesting. This isn't a
really serious enquiry, I was just wondering how Ruby makes the determination
about what's defined when and how in these situations.

The Ruby parser determines local variables when it finds a symbol a a
LHS of an assigment expression. From that point on, any reference to
that symbol are treated as local variables. In the case of the ||=,
here you have the magic that tells that this is an assignment
expression:

https://github.com/ruby/ruby/blob/trunk/parse.y#L7404

      case '|':
        if ((c = nextc()) == '|') {
            lex_state = EXPR_BEG;
            if ((c = nextc()) == '=') {
                set_yylval_id(tOROP);
                lex_state = EXPR_BEG;
                return tOP_ASGN;
            }


When it finds ||=, that's an assignment expression, so the LHS is
considered a local variable.

Jesus.
F549641069ea6946c5cd63bbfb451cd7?d=identicon&s=25 WILLS, JAMAL A (Guest)
on 2013-10-24 14:53
(Received via mailing list)
> From: ruby-talk [mailto:ruby-talk-bounces@ruby-lang.org] On Behalf Of Corin
Schedler
>
> The mechanism that allows this particular paradigm in Ruby is the ||=
> operator itself. Many have waxed poetic about it [1] but the basic gist
> is that ||= acts very similarly to:
>
>   foo || foo = nil

I thought this was more like:

  foo = foo || nil

Jamal Wills
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2013-10-24 15:27
(Received via mailing list)
On Thu, Oct 24, 2013 at 2:52 PM, WILLS, JAMAL A <jw1496@att.com> wrote:
>         foo = foo || nil
>
> Jamal Wills


If you read the article posted above by Corin:
http://www.rubyinside.com/what-rubys-double-pipe-o...
you will see the full explanation. The difference is more apparent
with hashes.

Jesus.
Aa082c8b00a50928e5860dcd70bf2368?d=identicon&s=25 tamouse m. (tamouse_m)
on 2013-10-25 19:05
(Received via mailing list)
On Thu, Oct 24, 2013 at 5:08 AM, Jesús Gabriel y Galán
<jgabrielygalan@gmail.com> wrote:
>
> When it finds ||=, that's an assignment expression, so the LHS is
> considered a local variable.
>
> Jesus.

Awesome explanation. Thank you, Jesus.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.