[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

nil? and non-existent objects

François Montel

4/4/2007 7:25:00 PM

Why is it that the nil? method can sometimes be called on an object that
doesn't exist, and other times will return an error. Under what
circumstances can you call the nil? method on a non-existent object?

Consider:

>> puts x = 1 if x.nil?
=> 1
>> puts â??z is not definedâ?? if z.nil?
=> NameError: undefined local variable or method â??zâ??

Someone mentioned that = has higher precedence than if, so it could be
that in the first statement x is assigned 1 before the conditional
statement is run. However, x.nil? would then always return false.

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

10 Answers

Emmanuel Oga

4/4/2007 7:46:00 PM

0

I think is because of the ruby's analisis on the scope. That is, in:

puts x = 1 if x.nil?

ruby sees x in the scope even if it is never accesed nor asigned, but in

puts â??z is not definedâ?? if z.nil?

z is never in scope, because it is present only inside a string, it does
not appear anywhere before the call of the method "nil?"

you can do:

{ z } if z.nil? => returns nothing of nothings (not nil nor false) ruby
don't complain because z is seen in the scope

Also works:

"HELLO #{an_unique_var_name}" if an_unique_var_name.nil?

-------------------------------------------------------------------------------

François Montel wrote:
> Why is it that the nil? method can sometimes be called on an object that
> doesn't exist, and other times will return an error. Under what
> circumstances can you call the nil? method on a non-existent object?
>
> Consider:
>
>>> puts x = 1 if x.nil?
> => 1
>>> puts â??z is not definedâ?? if z.nil?
> => NameError: undefined local variable or method â??zâ??
>
> Someone mentioned that = has higher precedence than if, so it could be
> that in the first statement x is assigned 1 before the conditional
> statement is run. However, x.nil? would then always return false.


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

Gavin Kistner

4/4/2007 7:51:00 PM

0

On Apr 4, 1:25 pm, "François Montel" <zeroh...@gmail.com> wrote:
> Why is it that the nil? method can sometimes be called on an object that
> doesn't exist, and other times will return an error. Under what
> circumstances can you call the nil? method on a non-existent object?
>
> Consider:
>
> >> puts x = 1 if x.nil?
> => 1
> >> puts 'z is not defined' if z.nil?
>
> => NameError: undefined local variable or method 'z'

Consider this:

irb(main):001:0> puts x=1 if x
=> nil

irb(main):002:0> puts y if y=1
(irb):2: warning: found = in conditional, should be ==
NameError: undefined local variable or method `y' for main:Object

irb(main):003:0> if z=1 then puts z end
(irb):3: warning: found = in conditional, should be ==
1
=> nil

The difference between them is the order in which Ruby sees the
assignment *when preparing* (syntax parsing), not during execution.
The 'y' and 'z' cases above should run the same way, but due to the
way Ruby checks to determine if a variable exists, it needs to see an
assignment earlier in the file than a reference to the value.

Chad Perrin

4/4/2007 8:12:00 PM

0

On Thu, Apr 05, 2007 at 04:46:12AM +0900, Emmanuel Oga wrote:
> I think is because of the ruby's analisis on the scope. That is, in:
>
> puts x = 1 if x.nil?
>
> ruby sees x in the scope even if it is never accesed nor asigned, but in
>
> puts ???z is not defined??? if z.nil?
>
> z is never in scope, because it is present only inside a string, it does
> not appear anywhere before the call of the method "nil?"

Is that a spec detail or an implementation detail? It might be nice to
know whether, assuming a stable language specification, that operational
characteristic might go away at some point.

--
CCD CopyWrite Chad Perrin [ http://ccd.ap... ]

Gary Wright

4/4/2007 8:19:00 PM

0


On Apr 4, 2007, at 3:25 PM, François Montel wrote:
> Why is it that the nil? method can sometimes be called on an object
> that
> doesn't exist, and other times will return an error. Under what
> circumstances can you call the nil? method on a non-existent object?

It is an artifact of the way the Ruby parser works and the syntactical
ambiguity of a method call with no arguments and local variables.

> Consider:
>
>>> puts x = 1 if x.nil?
> => 1

Here, the Ruby parser 'sees' the expression: 'x = 1' and concludes that
x must be a local variable. It sees the expression and makes the
determination about 'x' *before* it sees the method call: 'x.nil?'.
Once it has made that determination is considers 'x.nil?' as a method
call against the local variable 'x' and not as a method call for 'x'
relative to 'self'.

The net effect is that the local variable 'x' is willed into existence
by the parser (and defaults to nil). Since 'x.nil?'
evaluates to true, 'puts x = 1' is executed changing the value of x
to 1, which gets printed.

Consider a situation where x was a method call with an argument:

puts x = 1 if x('foo').nil?

In this case the parser sees no ambiguity, "x('foo')" must be a method
call even though it already saw 'x = 1' as a local variable assignment.

>>> puts ‘z is not defined’ if z.nil?
> => NameError: undefined local variable or method ‘z’

Here the parser hasn't seen 'z' until it comes across 'z.nil?'. It
makes the determination that z must be a method call. When the parsing
is complete and the statement is executed, Ruby tries to call 'z' in
the current context and finds that there really isn't a method
called 'z' and you get the Name Error.

Note that the *parser* can't determine if the method z exists or not.
It is only at the time of execution that that can be determined:

def tricky
def z; 'z exists!'; end
end

puts z rescue "z isn't defined" # => "z isn't defined"
tricky
puts z # => "z exists!"

Here is another example

if w # parser sees this as a method call, NameError
# exception is raised.
puts w = 42 # parser sees this as local variable assignment
# but it never executes
end

Now consider (in a new session of ruby or irb):

puts w = 42 if w # parser sees w as a local variable and initializes
# w to nil, puts never executes




François Montel

4/4/2007 8:58:00 PM

0

Thanks, everyone, for the thorough explanation. This is all very
helpful/educational.

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

Brian Candler

4/4/2007 9:27:00 PM

0

On Thu, Apr 05, 2007 at 04:25:23AM +0900, Fran?ois Montel wrote:
> Why is it that the nil? method can sometimes be called on an object that
> doesn't exist, and other times will return an error. Under what
> circumstances can you call the nil? method on a non-existent object?
>
> Consider:
>
> >> puts x = 1 if x.nil?
> => 1
> >> puts ???z is not defined??? if z.nil?
> => NameError: undefined local variable or method ???z???

Maybe easier to understand if you consider this:

if false
x = 0
end

puts x.inspect # => nil

When the file is *parsed*, the assignment "x = 0" flags "x" as a
local variable from that point onwards within the scope. This is true
whether or not it is actually executed; it's a parse-time decision as to
whether "x" is a local variable or a method call with implicit receiver.

Regards,

Brian.

Jamal Soueidan

4/4/2007 9:57:00 PM

0

François Montel wrote:
> Why is it that the nil? method can sometimes be called on an object that
> doesn't exist, and other times will return an error. Under what
> circumstances can you call the nil? method on a non-existent object?
>
> Consider:
>
>>> puts x = 1 if x.nil?
> => 1
>>> puts â??z is not definedâ?? if z.nil?
> => NameError: undefined local variable or method â??zâ??
>
> Someone mentioned that = has higher precedence than if, so it could be
> that in the first statement x is assigned 1 before the conditional
> statement is run. However, x.nil? would then always return false.

You could also fix it this way :)

----------------------------------------------

def x
@x
end

def x=(val)
@x = val
end

puts x=1 if x.nil?

----------------------------------------------

This would output: 1


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

François Montel

4/4/2007 10:12:00 PM

0

Jamal Soueidan wrote:

> You could also fix it this way :)
>
> ----------------------------------------------
>
> def x
> @x
> end
>
> def x=(val)
> @x = val
> end
>
> puts x=1 if x.nil?
>
> ----------------------------------------------
>
> This would output: 1

Actually, it needs no fixing, or the def statements. The explanation
(thanks, Brian, et al) is that "x=1 if x.nil?" works because when the
parser sees 'x=1' it flags x as a local variable and creates it,
assigning it the value nil. Only then does it execute x.nil?, which
returns a value since x now exists.

In other words, if there is any reference to a new local variable in
your code, even if that reference is not executed (as in Brian's
example), the local variable is created and assigned a nil value.

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

Brian Candler

4/5/2007 5:34:00 AM

0

On Thu, Apr 05, 2007 at 06:56:46AM +0900, Jamal Soueidan wrote:
> François Montel wrote:
> > Why is it that the nil? method can sometimes be called on an object that
> > doesn't exist, and other times will return an error. Under what
> > circumstances can you call the nil? method on a non-existent object?
> >
> > Consider:
> >
> >>> puts x = 1 if x.nil?
> > => 1
> >>> puts ???z is not defined??? if z.nil?
> > => NameError: undefined local variable or method ???z???
> >
> > Someone mentioned that = has higher precedence than if, so it could be
> > that in the first statement x is assigned 1 before the conditional
> > statement is run. However, x.nil? would then always return false.
>
> You could also fix it this way :)
>
> ----------------------------------------------
>
> def x
> @x
> end
>
> def x=(val)
> @x = val
> end
>
> puts x=1 if x.nil?
>
> ----------------------------------------------
>
> This would output: 1

I think you should check your work before posting (I do)

Run this:

def x
puts "calling main.x"
@x
end

def x=(val)
puts "calling main.x="
@x = val
end

puts x=1 if x.nil?

You'll see that your two methods are never called, so they don't make any
difference.

Jamal Soueidan

4/5/2007 9:23:00 AM

0

Brian Candler wrote:
> On Thu, Apr 05, 2007 at 06:56:46AM +0900, Jamal Soueidan wrote:
>> > => NameError: undefined local variable or method ???z???
>> @x
>> This would output: 1
> I think you should check your work before posting (I do)

true, they are not?

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