Confusion with the if modifier

Look the below code

(arup~>~)$ pry --simple-prompt

x = 1
=> 1

puts “x is 1” if x == 1
x is 1
=> nil

puts “x is 1” if x != 1
=> nil

The above code is telling, first checking the conditions, then execute
the body puts .... I agree this, why then error from the below code ?

puts a if a = 0.zero?
NameError: undefined local variable or method a' for main:Object from (pry):4:inpry

Hi Arup.

If you run your snippet with debugging on (-d) you will see a warning
about an unused variable…
For example:

foo_bar.rb

foo = 1
puts foo
puts “foo is 1” if foo == 1
puts “bar is 1” if bar != 1

=> Exception `NameError’ at foo_bar.rb:6 - undefined local variable

or method `bar’ for main:Object

if() when used as a modifier has its own context… its scope.
So the assignment is never seen outside of the if and ‘bar’ it’s
undefined.

This works:

if (bar = 1+1) == 2
puts “bar is 2? yup! (#{bar})”
end

because the block that the if statement takes is also within the same
scope as the assignment.
.
Hope it helps

On Sat, Feb 8, 2014 at 4:30 PM, Arup R. [email protected]
wrote:

The above code is telling, first checking the conditions, then execute
the body puts .... I agree this, why then error from the below code ?

puts a if a = 0.zero?
NameError: undefined local variable or method a' for main:Object from (pry):4:in pry


Posted via http://www.ruby-forum.com/.

Eddie

Edoardo R. wrote in post #1136041:

Hi Arup.

if() when used as a modifier has its own context… its scope.
So the assignment is never seen outside of the if and ‘bar’ it’s
undefined.

See another snippet :

puts “hi” if x = 2
(pry):11: warning: found = in conditional, should be ==
hi
=> nil

x
=> 2

How then here x does print 2 ?

Because the assignment of x happens and it’s not lost…

puts "x before all: "
puts “#{x.inspect}” rescue puts “x is nil”
puts "x before the if: "
puts “#{x.inspect}” if(x = 2) rescue puts “x is still nil”
puts “but x after the if: #{x.inspect}”

On Sat, Feb 8, 2014 at 5:13 PM, Arup R. [email protected]
wrote:

(pry):11: warning: found = in conditional, should be ==
hi
=> nil

x
=> 2

How then here x does print 2 ?


Posted via http://www.ruby-forum.com/.

Eddie

On Sat, Feb 8, 2014 at 9:57 AM, Edoardo R. [email protected]
wrote:

Hi Arup.

If you run your snippet with debugging on (-d) you will see a warning
about an unused variable…
For example:

Your example doesn’t show such a warning.

if() when used as a modifier has its own context… its scope.
So the assignment is never seen outside of the if and ‘bar’ it’s undefined.

I believe this is incorrect and sows confusion. In reality, the reason
puts a if a = 0.zero? fails if a hasn’t been defined is because the parser
scans strictly from left to right looking for assignments. When it finds
an
assignment, it considers the left side of that assignment to be a valid
variable from there to the end of the scope. It doesn’t backtrack into
the
portion of the line before a modifier-if, so puts a is unable to
resolve
the variable a.

Földes László wrote in post #1136082:

Edoardo R. wrote in post #1136041:

[1] pry(main)> puts a if a = 0.zero?
NameError: undefined local variable or method a' for main:Object from (pry):1:inpry
[2] pry(main)> a
=> true
[3] pry(main)>

If anything that is defined gets into this inner scope and anything that
is defined (or modified) inside the inner scope gets out, then this is
not really a scope…

Another example, which doesn’t create a noise like local variable in my
first post.

(arup~>~)$ pry --simple-prompt

puts meth if eval(‘def meth;12;end’).nil?
12
=> nil

Edoardo R. wrote in post #1136041:

if() when used as a modifier has its own context… its scope.
So the assignment is never seen outside of the if and ‘bar’ it’s
undefined.

But ‘a’ gets defined after the error. Does it mean that it first gets
defined in the inner scope and passed to the outer scope?

[1] pry(main)> puts a if a = 0.zero?
NameError: undefined local variable or method a' for main:Object from (pry):1:inpry
[2] pry(main)> a
=> true
[3] pry(main)>

If anything that is defined gets into this inner scope and anything that
is defined (or modified) inside the inner scope gets out, then this is
not really a scope…

Dear Arup R.,

I think this is because method lookup is different from variable
lookup in Ruby.

Try this on a file (because inside pry or irb is hard to deal with
method_missing).

#!/usr/bin/env ruby

If no local variable is found,

it begins the method lookup that ends calling

the method_missing chain until the last one raises the error

begin
p undefined_name if true
rescue
puts “Raised an error”
else
puts “No error at all”
end

def method_missing(method, *args)
“I’m a method”
end

When no method is found,

It hits the method_missing and do what is defined on it

so… returns “I’m a method” without raising any errors.

puts

begin
p undefined_name if true
rescue
puts “Raised an error”
else
puts “No error at all”
end

undefined_name = “I’m a local-variable”

Now a local-variable with the same name is found (before the method)

puts

begin
p undefined_name if true
rescue
puts “Raised an error”
else
puts “No error at all”
end

If we need to disambiguate it, for the method we need to prepend the

object will be sending it to.

self.undefined_name vs. undefined_name

puts

begin
p self.undefined_name if true
rescue
puts “Raised an error”
else
puts “No error at all”
end

Abinoam Jr.