Home > other >  How does variable assignment works in ruby?
How does variable assignment works in ruby?

Time:02-15

Ruby version: ruby 2.6.7p197 (2021-04-05 revision 67941) [x86_64-linux]

Rails gem version: 6.0.1


Simple question, I have this example on rails console

As expected, if I try to call a non existent variable, I got an error

irb(main):007:0> value
# Traceback (most recent call last):
#         2: from (irb):7
#        1: from (irb):7:in `rescue in irb_binding'
# NameError (undefined local variable or method `value' for main:Object)

But if I try to do the following example

(value = 1) if value.present?

It returns nil for some reason, the first scenario this happenned there was no parenthesis, I thought it was defining the variable and then returning a value of nil, but then I tried with it and just happened again (I tried other variable because ruby counted that as a defined variable)

OBS: I tried the same scenario on raw irb and it raised me an error, this only happens on rails console

EDIT: It only raised an error because I didn't realized that '.present?' is a rails method, but if I change my syntax to

(value = 1) if value

the same behaviour happens


Why does that happen? Shouldn't a NameError be raised?

CodePudding user response:

Ruby works such way, please look the docs

The local variable is created when the parser encounters the assignment, not when the assignment occurs:

a = 0 if false # does not assign to a

p local_variables # prints [:a]

p a # prints nil

And other interesting thing:

Another commonly confusing case is when using a modifier if:

p a if a = 0.zero?

Rather than printing “true” you receive a NameError, “undefined local variable or method 'a'”. Since ruby parses the bare a left of the if first and has not yet seen an assignment to a it assumes you wish to call a method. Ruby then sees the assignment to a and will assume you are referencing a local method.

The confusion comes from the out-of-order execution of the expression. First the local variable is assigned-to then you attempt to call a nonexistent method.

So you can

  • Related