Question on if / defined?()

assuming x is not defined, why does the statement

x = true if !defined?(x)

produce x is nil ?

y = true if !defined?(x)

is no different

this however works fine:

if !defined?(x)
x = true
end

On Tue, Aug 17, 2010 at 12:05 PM, Jedrin [email protected] wrote:

assuming x is not defined, why does the statement

x = true if !defined?(x)

produce x is nil ?

Because x is defined, this happens at parse time so it doesn’t matter
if the assignment is executed or not.

y = true if !defined?(x)

is no different

Not by itself

y = true if !defined? x

y # => true

I’m guessing you had this in a program AFTER something which defined x

this however works fine:

if !defined?(x)
because at this point x is NOT defined since the parser hasn’t yet seen
it.
x = true
end

HTH


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Github: rubyredrick (Rick DeNatale) · GitHub
Twitter: @RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

Rick Denatale wrote:

I’m guessing you had this in a program AFTER something which defined x

The two statements were probably typed sequentioally. Consider the
outputs of two different irb sessions:

irb(main):001:0> y = true if !defined?(x)
=> true
irb(main):002:0> y
=> true
irb(main):003:0>

and

irb(main):001:0> x = true if !defined?(x)
=> nil
irb(main):002:0> x
=> nil
irb(main):003:0> y = true if !defined?(x)
=> nil
irb(main):004:0> y
=> nil
irb(main):005:0> x
=> nil
irb(main):006:0>

x was defined as nil.

js

Rick Denatale wrote:

Because x is defined, this happens at parse time so it doesn’t matter
if the assignment is executed or not.

Is this because when the parser sees ‘x = …’, Ruby automatically
assigns a reference to the variable x?

It seems to me that this is the only way that this behavior makes sense.

js

On Tue, Aug 17, 2010 at 6:30 PM, John S. [email protected]
wrote:

Rick Denatale wrote:

Because x is defined, this happens at parse time so it doesn’t matter
if the assignment is executed or not.

Is this because when the parser sees ‘x = …’, Ruby automatically
assigns a reference to the variable x?

I think that’s correct, but I’d welcome confirmation from those more
knowledgeable about this.

irb
x
#=> NameError: undefined local variable or method ‘x’ for main:Object
x = x
#=> nil

Sort of assigning itself by it’s own bootstraps?

Here’s a simpler example:

if false
x = 123
end
puts x # nil

x is defined, and has value nil. What has happened?

When the code is parsed (before it is executed at all, just when Ruby
is building an in-memory representation of the program), if Ruby sees an
assignment like x = … then it marks x as being a local variable,
reserving a slot for it on the stack.

Whether the assignment is actually executed later or not is irrelevant.
From this point onwards to the end of the current scope, x is defined,
and is a local variable.

Why does ruby do this? There is a local variable / method call
ambiguity. Because you don’t declare variables in Ruby, and because a
method call doesn’t need parentheses after it, a bare “x” could be
either retrieving the value of x, or it could be calling the method x
with no arguments.

This simple parse-time algorithm decides in advance which you meant,
without you having to declare it.

puts x              # undefined local variable or method `x'

def x
  "Method x"
end
puts x              # Method x

x = 123
puts x              # 123

At this point it’s decided that ‘x’ is a local variable, although you
can still force a method call instead:

puts x              # 123
puts self.x         # Method x
puts x()            # Method x

Shy of looking at the code:
The following appears that when using the ternary operator it sheds a
little
light on the state of x.state, in our case true or false.

In the first case x is assigned to true or false. Its forced into a
state.
Now we follow up with y returning false, also. In either case, we set
the
receiver (lvalue) to a known

! irb
ruby-1.9.2-preview3 > x = !defined?(x) ? true : false
=> false
ruby-1.9.2-preview3 > x
=> false
ruby-1.9.2-preview3 > y = !defined?(x) ? true : false
=> false
ruby-1.9.2-preview3 > y
=> false

When we go into the assignment x=true the if statement will execute and
upon
its success will store true into the x variable. I am suggesting this x
variable must be instantiated as the line is digested by the compiler
and
therefore is instantiated as x with no assignment. Hence, we have one
state
true and the opposite is no state or nil

The result this statement finds it if false nil (no state) is reported
(returned) as the if has failed to fire and invoke the intended
statement…
No statement, nil.

ruby-1.9.2-preview3 > x = true if !defined?(x)
=> nil

However, x is untouched and is still set to false, below.

ruby-1.9.2-preview3 > x
=> false

ruby-1.9.2-preview3 > l = true if !defined?(x)
=> nil
ruby-1.9.2-preview3 > l
=> false
ruby-1.9.2-preview3 >

The result below seems to follow this thinking: If is fired and
assignment
is invoked and x than is assigned true.

ruby-1.9.2-preview3 > x = true if defined?(x)
=> true
ruby-1.9.2-preview3 > x
=> true
ruby-1.9.2-preview3 >

So, the statement on the left of an if Statement must be parsed and
instantiated for the compiler to have something to invoke on the if
statement being successful.

I would think this is a compiler decision of optimistic logic. The
reverse
of this cold be the firing than instantiates the statement to be invoked
which would be pessimistic and seems to be open up a rabbit hole that
may
pose a problematic recovery.