

Ruby statement modifiers behave differently than conditional statements - angilly
http://ryanangilly.com/post/304559058/ruby-statement-modifers-behave-differently-than

======
aaronblohowiak
I contend that if you are using defined? you are doing something wrong. local
variables should be _local_. If you don't know what exists in the current
scope, you are dealing with confusing code. Rails erb evaluation for partials
makes this mistake, and creates a poor reimplementation of function calls
where the function header is defined by the caller with the :locals =>{} hash.

~~~
pvg
Or at the very least you are likely to get terribly confused. The posters
confusion has absolutely nothing to do with conditionals and modifiers and is
entirely about Ruby variable definition and scoping semantics. In fact if you
broke one of his examples by reversing the conditional, the variable, the
assignment of which is never evaluated is still defined.

    
    
      >> a = 1
      => 1
      >> unless defined? a
      >>   b = 5
      >> end
      => nil
      >> defined? b
      => "local-variable"
      >> b
      => nil

~~~
aaronblohowiak
Right, variable definition happens as early as when the code is parsed, even
if it is never used.

------
figgs
The following is wrong. Only read the rest of this reply if you want to see
how dumb I am.

 _This is not a bug.

"a = 5 unless defined? a" is not meant to be equivalent to this:

    
    
      unless defined? a
         a = 5
      end
    

It is supposed to be (and is) equivalent to this:

    
    
      a = unless defined? a
            5
          end*

~~~
aaronblohowiak
this is wrong!

    
    
      >> a = 1 
      => 1
      >> b = 2
      => 2
      >> a = 3 unless b==2
      => nil
      >> a
      => 1
      >> a = unless b==2
      >> 2
      >> end
      => nil
      >> a
      => nil
    

The difference is in the variable definition semantics, _not_ in the
assignment semantics. Please do not spread this misinformation.

~~~
figgs
My bad. Thanks for clarifying that.

------
tmm1

      >> if false
      >>   a = 1
      >> end
    
      >> defined? a
      => "local-variable"
    
      >> a
      => nil

~~~
india
That explains it! It does break the principle of least surprise though...

------
Locke
Yes, they are different. For example:

    
    
        def ex1
          a = 5
    
          if a
            puts "a: #{a}"
          end
        end
    
        def ex2
          if a = 5
            puts "a: #{a}"
          end
        end
    
        def ex3
          puts "a: #{a}"  if a = 5
        end
    

If we start with the code in ex1 and decide to shorten it, ex2 is okay
(although some people don't care for assignment in a conditional because it
could be confused for a typo). But, ex3 will raise an exception that 'a' has
not been defined.

I've just internalized using the longer form when using assignment in a
conditional.

~~~
chief
I think the article is wrong. His rewrite on line 06. should use if instead of
unless.

    
    
      $ irb
      >> b
      NameError: undefined local variable or method `b' for main:Object
      	from (irb):1
      >> if defined? b
      >>   b = 5
      >> end
      => nil
      >> b
      => nil
      >> defined? b
      => "local-variable"

~~~
angilly
No, it's using unless like I intended. But your example also demonstrates the
weird behavior. As a few people have pointed out here and over in the post
comments, the issue at hand isn't so much about statement modifiers as it is
about how Ruby 'defines' local variables.

Take this for example:

    
    
      ra:~$ irb
      a = irb(main):001:0> a = b
      NameError: undefined local variable or method `b' for main:Object
      	from (irb):1
      irb(main):002:0> defined? a
      => "local-variable"
      irb(main):003:0> 
    
    

It just so happens that using statement modifiers in the way I tried using
them brings this behavior to light.

------
rue
I think the main part was already covered, but there is one important detail
left uncorrected:

They are _expression_ modifiers and conditional _expressions_. Everything in
Ruby is an expression, not a statement.

