Why can't Ruby automatically cast variables?

One thing that annoys me about Ruby is that casting variables is
required:

i = 5
a = ‘logan’

puts a + i.to_s

Or

a=‘2’
b=3

puts a.to_i + b

Why can’t (or can?) Ruby just handle ‘puts a + i’ or ‘puts a+b’?

Joe

Joe R. MUDCRAP-CE wrote:

a=‘2’
b=3

puts a.to_i + b

Why can’t (or can?) Ruby just handle ‘puts a + i’ or ‘puts a+b’?

That’s not type casting, that’s type coercion. BIG difference.

Language-level automagical number / string type coercion is a Perl / PHP
-ism, and it’s a feature of those languages I loathe and despise for the
bugs it tends to cause.

Numbers are numbers. Strings are strings. Strings that happen to
represent numbers are still strings. Ruby is a strongly-typed language,
a Very Good Thing from a code maintainability point of view, that’s why
type coercion is always explicit.

Ruby sometimes does this on the library-function level, but in the
examples you described, the meaning is always ambiguous. Especially
since adding an integer to a string means the integer is considered to
be the ASCII code of a character.

If I do ‘logan’ + 115, does that mean I want the result to be ‘logans’
because 115 is the ASCII code for ‘s’, should be ‘logan115’, or should
it be just 115 because ‘logan’ isn’t a number and thus automagically
coerces to 0? And for ‘2’ + 3 it gets even worse, which of those should
be coerced to what and why?

This is, in my opinion, best left explicit. The possible interpretations
are way, way too numerous and difficult to keep in one’s head at once.

David V.

Joe R. MUDCRAP-CE wrote:

a=‘2’
b=3

puts a.to_i + b

Why can’t (or can?) Ruby just handle ‘puts a + i’ or ‘puts a+b’?

It does. It just doesn’t handle it the way you might prefer. If Ruby
did automatic coercion, then someone else would wonder why Ruby doesn’t
"correctly: handle the ‘+’ operation.

Given this code:

a=‘2’
b=3

puts a+b

This is sending the message ‘+’ to the String object referenced by ‘a’.
Strings have a particular implementation of the ‘+’ message, and it
assumes that the arguments will be something that implements certain
behavior. (I.e., is sufficiently String-like ).

By default, the above code barfs with “… can’t convert Fixnum into
String (TypeError)”

You can teach the Integer class how to stringify itself, though:

class Integer
def to_str
self.to_s
end
end

But note that there is an important side-effect: Integers mistakenly
used in place of a String will now silently convert themselves, which
may not be the behavior you (or users of your code) will always want.

Ruby has strong dynamic typing; objects need only respond to the set
messages your code needs to send to them in order to be useful (AKA duck
typing). That’s the dynamic part. But Ruby will not automagically alter
the behavior of objects. That’s the strong part.


James B.

“Blanket statements are over-rated”

Joe R. MUDCRAP-CE wrote:

David V. wrote:

Point taken. I can’t imagine wanting to do ‘logan’ + 115 and have it be
‘logans’ (as opposed to just doing ‘logan’ + ‘s’), but I’m sure there
are applications for adding ASCII values.

That’s a convention / burp of Ruby. Indexing a string with an integer
instead of a Range returns the ASCII code of the character at that
position. Adding an integer to a string does cause an exception to be
thrown. However,

irb(main):001:0> foo = ‘quux’
=> “quux”
irb(main):002:0> foo[-1] = 115
=> 115
irb(main):003:0> foo
=> “quus”
irb(main):004:0> foo[-1] = ‘bar’
=> “bar”
irb(main):005:0> foo
=> “quubar”

That means the behaviour is reflexive and at least somewhat consistent,
a minor redeeming quality.

As far as I know, in Ruby 1.9, and 2.0, indexing a String will return a
one-character string instead of making that a special case, so the need
for this type conversion will disappear.

(Technically, an int -> char conversion isn’t a change of data. However,
since Ruby doesn’t have the char data type, the above behaviour is
contextual overloading of the integer datatype - a special case when an
integer isn’t treated as a character, and that is, at least for me,
confusing.)

That’s not type casting, that’s type coercion. BIG difference.

Hmm, what’s the difference? IIRC, PHP’s docs referred to (int)$stringvar
as casting, which seems the same as to_s, to_i, etc.

Casting is usually an explicit conversion, coercion an implicit one. PHP
documents are correct on that, except PHP performs a much larger set of
type conversions that way than most other languages where type casting
appears (C, Java; C++ and C# let you overload type conversion, but don’t
do type conversion between wildly heterogenous types out of the box).
Noted explicitly, it’s not really a problem, since you don’t have to pay
attention to the context to see whether the type conversion does or does
not happen.

Coercion is an implicit conversion that the language runtime does for
you. The problem with it is that it’s not readily visible when it
happens, and tends to contribute to language “gotchas” - unobvious rules
you have to keep in your head when reading code. Ruby has a one of those
with String#match() - if the argument to the method is a String, it gets
coerced to a Regexp. Of course, I had to fire up irb to find out if the
method receiver or the argument is the coerced object.

Extensive “magical” behaviour of a programming language in the long term
leads to people ending up with more of the language in their head
especially when not dealing with write-only code to maintain it, and
keeps information needed to read the code out of sight. It isn’t harmful
in some cases - for example for String#format, the printf-specifiers
already indicate that a certain argument will be interpreted for example
as an integer, and it’s redundant to have to restate this. It’s not good
when the coercion would be ambiguous though, and actively harmful
(PHPism) when conversion doesn’t ever fail cleanly - like a string that
doesn’t contain a single number that coerces into 0.

David V.

David V. wrote:

Point taken. I can’t imagine wanting to do ‘logan’ + 115 and have it be
‘logans’ (as opposed to just doing ‘logan’ + ‘s’), but I’m sure there
are applications for adding ASCII values.

That’s not type casting, that’s type coercion. BIG difference.

Hmm, what’s the difference? IIRC, PHP’s docs referred to (int)$stringvar
as casting, which seems the same as to_s, to_i, etc.

Joe

Joe R. MUDCRAP-CE wrote:

a=‘2’
b=3

puts a.to_i + b

Why can’t (or can?) Ruby just handle ‘puts a + i’ or ‘puts a+b’?

How would it know whether you wanted to concatenate the two, or add
them?

Sammy L. wrote:

Joe R. MUDCRAP-CE wrote:

a=‘2’
b=3

puts a.to_i + b

Why can’t (or can?) Ruby just handle ‘puts a + i’ or ‘puts a+b’?

How would it know whether you wanted to concatenate the two, or add
them?

By reading my mind.

Joe

On 9/30/06, Joe R. MUDCRAP-CE [email protected] wrote:

Hmm, what’s the difference? IIRC, PHP’s docs referred to (int)$stringvar
as casting, which seems the same as to_s, to_i, etc.

PHP is not to be taken as an authority on anything. Especially Ruby.

(int)$stringvar is casting. stringvar.to_i is conversion. The
automatic handling of such conversion is called coercion.

-austin

On 30/09/06, Joe R. MUDCRAP-CE [email protected] wrote:

a=‘2’
b=3

puts a.to_i + b

Why can’t (or can?) Ruby just handle ‘puts a + i’ or ‘puts a+b’?

I don’t suggest you actually use this, but:

class String
def coerce(lhs)
[lhs, self.to_i]
end

alias_method :old_plus, :+
def +(rhs)
  if rhs.is_a?(Numeric)
    return rhs + self
  else
    return old_plus(rhs)
  end
end

end

1 + ‘1’ #=> 2

‘2’ + 2 #=> 4

‘foo’ + ‘bar’ #=> “foobar”

Paul.