Igor Pirnovar wrote in post #1082740:
> You are misleading us here with {{ def bar; "Method bar"; end }} before
> the assignment in {{ bar if bar = 123 }}, because parser now thinks that
> it sees the method bar.

On the contrary, it is you who are misleading people with your 
inaccurate information.

In your defence, I will say that ruby is a language which is not 
formally specified or documented, and therefore it is easy to come up 
with misinterpretations of what you see. However, there are people on 
this list who will try to enlighten you, if you will take the trouble to 
listen.

> Try it with a new variable, that is not shadowed
> by another token like in your case the bar method, and you will see,
> that interpreter exits with the error! For instance:
>
>    p "v5:#{v5 if ((v5='created')!='')}"  #=> FAILS with:
>     # t.rb:28:in `<main>': undefined local variable \
>     # or method `v5' for main:Object (NameError)

Indeed it does, and the error message says "undefined local variable or 
method"

Ruby has interpreted the first v5 as a method call, because no local 
variable assignment statement exists lexically earlier in the scope. So 
it has tried to call method v5(), and failed.

However it cannot know whether the programmer intended v5 to be a 
variable or method. It could be that you intended to use a variable, but 
mistyped the name:

v5 = nil
puts vv5   # Oops, I mistyped the variable name

vv6 = nil  # Oops, I mistyped the variable name at assignment time
puts v6

Or it could be that you intended to call a method but mistyped it:

def v7; "ok"; end
puts vv7   # Oops, I mistyped the method name

So the best that Ruby can say is "undefined local variable or method". 
But what it actually means is: v5 is *definitely* not a local variable 
at this point, so I tried invoking it as a method, but there is no 
method called v5 at this point in time.

Note: whether v5 exists as a method or not can only be known at runtime, 
because methods are created dynamically as the program runs.

> Precedence may not be important, though I am not sure it is not, since
> the run-time must wait for the condition to be evaluated, therefore  it
> will execute the assignment inside the 'if' expression in accordance
> with precedence, namely prior 'if' expression itself is evaluated, hence
> allowing the evaluation of the expression in front of the conditional,
> the run-time was waiting for.

Wrong. The resolution of the variable name / method call ambiguity is 
not done at run-time. It is done at *parse* time, when the source file 
is being read in and the AST is being built, before the AST is executed.

If you don't believe me, then try making a source file which cannot be 
parsed, like this:

puts "hello"
class Foo    # missing end

You will see something like this:

syntax error, unexpected $end

But notice that the word "hello" does not appear on your screen. This is 
because execution cannot start until the file has been completely parsed 
from top to bottom.  Balancing class/end and def/end is a parse-time 
activity.

Now, it is during this *parsing* phase that the decision is made as to 
whether a bareword 'foo' is to be interpreted as a method call or as a 
local variable reference. And this happens before even one statement 
from this file has been executed.

> Also, the fact that {{ puts var||='n/a' if var=123 }} works as expected,
> and {{ puts var if var=123 }} does not, proves that evaluation here is
> right-to-left regardless of the fact that parser works in the opposite
> direction, after all, if parser would react to the first assignment it
> encountered in 'strictly' left-to-right fashion the result should be
> 'n/a' and not 123 that was evaluated last.

var||='n/a' is an assignment to var and therefore springs a local 
variable into existence at that point lexically. You can consider it as 
a shortcut for var = var || 'n/a', although it is not exactly like that.

The execution sequence obviously requires the 'if' condition to be 
evaluated before the LHS can be conditionally executed.

if var = 123     # assigns 123 to var, evaluates as true, hence LHS is 
run

puts var||='n/a'   # prints 123, because var has already been assigned 
to

So evaluation is right-before-left, at the time where the AST is 
executed. This still does not change the fact that it is parsed 
left-to-right.

Hence, if you have not assigned to var previously, then
    puts var if var=123
is parsed as
    puts var() if var=123

It treats the first bareword 'var' to be resolved as a method call; it 
will fail unless a method called 'var' has been defined.

The final point you need to be clear on: whether an assignment is 
*executed* or not makes no difference. It's simply whether it is parsed 
as one. So for example:

if false
  baz = 123
end
puts baz    # prints nil - does not give an error

Regards,

Brian.

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