NilClass and automatic conversion question [long]

Hi gurus,

(even if I read the ng/list for some month, I never saw this
questions, so i put it myself.
Anyway, those could be old question, tuby-talk is a huge list an
it’s easy to miss something, sorry…)

DISCLAIMER: the above is done with 1.6.8
( little testing with ruby-1.8.0-20021226 win32 seem to give the same
result )

Why this don’t work:

irb(main):001:0> a=“strink”
=> "strink"
irb(main):002:0> puts a+1
TypeError: failed to convert Fixnum into String
from (irb):2:in `+'
from (irb):2

and this does:

irb(main):003:0> puts a+1.to_s
strink1
=> nil

It seems to me that “puts” works using .to_s on every object ,
String.+ is not ?

And… if ruby knows that 1 is Fixnum, anf that it should be translated
to a String… what way it tryes to do this ?

this actually is the same with everything!

irb(main):025:0> b=nil
=> nil
irb(main):026:0> a=“string”
=> "string"
irb(main):027:0> a+=b
TypeError: failed to convert nil into String
from (irb):27:in +' from (irb):27 irb(main):028:0> b=true => true irb(main):029:0> a+=b TypeError: failed to convert true into String from (irb):29:in+'
from (irb):29

1.1
but…

(a=3, b=nil)

irb(main):035:0> a+=b
TypeError: nil can’t be coerced into Fixnum
from (irb):35:in `+'
from (irb):35

I still think 3+nil should simply be 3, but anyway, why we’ve got a
different result from those above?

What’s the difference beetween “convert” and “coerce”
(don’t think about real life difference please :slight_smile:

(and, from “string+nil”, we go to “nil+string”)

(NilQuestion “nil+”)

why nil does’nt have a “+” method?
It seem reasonable (and useful) having nothing +something giving back
nothing.

Maybe that’s impossible in the same way Fixnum.++ is ?

(NilQuestion “puts”)

Why :

irb(main):012:0> puts nil
nil
=> nil
irb(main):013:0> puts nil.to_s

=> nil

It seems obvious that my previous assertion (puts using to_s) is wrong
, or we are always checking that an obj is not null ?
( lot of cheking?)

Anyway, I understand that writing “nil” when a var is actually nil is
good for debugging, but why to_s should not give the same?

(maybe that’s related to things like this :

irb(main):017:0> a=nil
=> nil
irb(main):018:0> b=a.to_s+“bla”
=> “bla”

and, well, I think that could make sense.
BTW, having NilClass.+ eliminates this difference :slight_smile: )

Gabriele,

Why this don’t work:

irb(main):001:0> a=“strink”
=> “strink”
irb(main):002:0> puts a+1
TypeError: failed to convert Fixnum into String
from (irb):2:in `+’
from (irb):2

and this does:

irb(main):003:0> puts a+1.to_s
strink1
=> nil

It seems to me that “puts” works using .to_s on every
object , String.+ is not ?

And… if ruby knows that 1 is Fixnum, anf that it should
be translated to a String… what way it tryes to do this ?

Your misunderstanding is in the definition of "every object".  In your

example, puts only sees 1 object: the result of the expression (a+1). For
example:

irb(main):001:0> a=“strink”
=> “strink”
irb(main):002:0> a+1
TypeError: failed to convert Fixnum into String
from (irb):2:in `+’
from (irb):2

You get the expected result if you pass the two parameters separately:

irb(main):003:0> puts a,1
strink
1
=> nil

The same reasoning applies to ("strink"+=nil), ("strink"+=true), and

(3+=nil).

(a=3, b=nil)

irb(main):035:0> a+=b
TypeError: nil can’t be coerced into Fixnum
from (irb):35:in `+’
from (irb):35

I still think 3+nil should simply be 3, but anyway,
why we’ve got a different result from those above?

The reason you get a different error message for (3+=nil) is that ruby

is trying to turn nil into a number instead of a string.

What’s the difference beetween “convert” and “coerce”

Since ruby has three built-in classes for numbers, ruby always tries to

“coerce” a class into the desired numeric class. For example when ruby sees
the expression (5.4 + 3), it tries to coerce the (3) - which is class
Fixnum - into a Float.

(and, from “string+nil”, we go to “nil+string”)

(NilQuestion “nil+”)

why nil does’nt have a “+” method?
It seem reasonable (and useful) having nothing
+something giving back nothing.

I don't have a definitive answer to this, but I believe that nil is

designed to represent “no object”, even though it (like most everything else
in ruby) actually is an object. Given this definition, I do not believe
that nil should support any arithmetic methods. Also, this would lead to
silent failures of expressions like (a = b + c) if b happened to be nil.

Why :

irb(main):012:0> puts nil
nil
=> nil
irb(main):013:0> puts nil.to_s

=> nil

It seems obvious that my previous assertion (puts using to_s)
is wrong, or we are always checking that an obj is not null ?

This is a good question.  puts should be calling to_s on all of its

parameters, but for some reason, nil is being handled differently. Perhaps
someone else can explain this inconsistency.

- Warren Brown

1)

Why this don't work:

irb(main):001:0> a="strink"
=> "strink"
irb(main):002:0> puts a+1
TypeError: failed to convert Fixnum into String
        from (irb):2:in `+'
        from (irb):2

and this does:

irb(main):003:0> puts a+1.to_s
strink1
=> nil

Same question asked recently, see thread starting at [ruby-talk:63340]

The answer generalises to nil.

I still think 3+nil should simply be 3

You can override the '+' method on Fixnum if you want this to occur, but the
default Ruby behaviour is sensible. nil means either 'no object' or
'uninitialised variable', and usually trying to add one of these would be an
error. If you're sure that's what you want, use 'to_i'.

It seem reasonable (and useful) having nothing +something giving back
nothing.

Maybe, but 'nil' isn't really the same as "zero" or "an empty string"

irb(main):012:0> puts nil
nil
=> nil
irb(main):013:0> puts nil.to_s

=> nil

It seems obvious that my previous assertion (puts using to_s) is wrong
, or we are always checking that an obj is not null ?
( lot of cheking?)

I think puts is calling the 'inspect' method there, but I'm not sure.

Anyway, I understand that writing "nil" when a var is actually nil is
good for debugging, but why to_s should not give the same?

Because it gives a way to get the behaviour you asked for earlier, if you
are explicit about it. e.g. if you want to concatenate a string with a
variable which might be nil, use to_s:

   a = "hello"
   b = nil
   c = a + b.to_s
   puts c >> "hello"

In the same way, if you want to add a number which might not be a number,
use to_i:

   a = "53 bananas"
   b = nil
   c = a.to_i + b.to_i
   puts c >> 53

Regards,

Brian.

···

On Fri, Feb 07, 2003 at 11:36:55PM +0900, gabriele renzi wrote:

Gabriele,

Your misunderstanding is in the definition of “every object”. In your
example, puts only sees 1 object: the result of the expression (a+1). For
example:

irb(main):001:0> a=“strink”
=> “strink”
irb(main):002:0> a+1
TypeError: failed to convert Fixnum into String
from (irb):2:in `+’
from (irb):2

You get the expected result if you pass the two parameters separately:

yes, I got this, I just pointed that puts uses to_s and String.+ does
not.
Sorry, my english is not so good and I’vew got some trouble trying to
explain myself :slight_smile:

What’s the difference beetween “convert” and “coerce”

Since ruby has three built-in classes for numbers, ruby always tries to
“coerce” a class into the desired numeric class. For example when ruby sees
the expression (5.4 + 3), it tries to coerce the (3) - which is class
Fixnum - into a Float.

thanks! that’s obvious once you explained it to me :slight_smile:

I don’t have a definitive answer to this, but I believe that nil is
designed to represent “no object”, even though it (like most everything else
in ruby) actually is an object. Given this definition, I do not believe
that nil should support any arithmetic methods. Also, this would lead to
silent failures of expressions like (a = b + c) if b happened to be nil.

That’s true, but i think I could use something like

if a && b && c
(a=b+c)
else

but, sure, this could put in hidden bugs…

···

On Sat, 8 Feb 2003 00:59:16 +0900, “Warren Brown” wkb@airmail.net wrote:

thanks for the answers

···

On Sat, 8 Feb 2003 00:59:42 +0900, Brian Candler B.Candler@pobox.com wrote: