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:in `__pry__'

···

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

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 Rakshit <lists@ruby-forum.com> wrote:

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:in `__pry__'

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

--

Eddie

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.

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

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.

···

On Sat, Feb 8, 2014 at 9:57 AM, Edoardo Rossi <edd.rossi@gmail.com> wrote:

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 Rakshit <lists@ruby-forum.com> wrote:
> 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:in `__pry__'
>
> --
> Posted via http://www.ruby-forum.com/\.

--

Eddie

Edoardo Rossi 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** ?

···

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

Edoardo Rossi 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:in `__pry__'
[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...

···

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

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 Rakshit <lists@ruby-forum.com> wrote:

Edoardo Rossi 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** ?

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

--

Eddie

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

Edoardo Rossi 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:in `__pry__'
[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

···

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

Dear Arup Rakshit,

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.

···

On Sat, Feb 8, 2014 at 8:15 PM, Arup Rakshit <lists@ruby-forum.com> wrote:

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

Edoardo Rossi 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:in `__pry__'
[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

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