Question

Ruby normally makes things easy. However, it doesn't allow implicitely converting a number to a string:

2.0.0p247 :010 > "a"+1
TypeError: no implicit conversion of Fixnum into String

Why is this when nearly every other language allows it, including Perl, PHP, Java and VBA?

Was it helpful?

Solution

Languages that have implicit conversion to string usually have it for all types, not just numbers. Implicit conversions are usually bad if you want strong typing, type errors that could have been discovered in compile time(in case of compiled static-typed languages) or as exceptions in runtime(in case of interpreted or dynamic-typed languages) may turn into logic errors(the worst kind of error) or unrelated exceptions.

Some languages are willing to deal with this to have a simple string syntax for creating strings, but Ruby doesn't need it because it has string interpolation:

[1] pry(main)> "a"+1
TypeError: no implicit conversion of Fixnum into String
from (pry):1:in `+'
[2] pry(main)> "a#{1}"
=> "a1"

OTHER TIPS

First, to clear up some misconceptions...

perl and php

Perl and php do not have implicit conversion from number to string.

Consider the code (written as perl to get the warnings, but you can run it as php also and get the same (sans warnings) results):

#!/usr/bin/perl

use strict;
use warnings;

print "a" + "b"; print "\n";
print "a" + 1; print "\n";
print "a" . 1; print "\n";
print 1 + 2; print "\n";
print 1 . 2; print "\n";

https://ideone.com/yZFiBn

When run this prints out:

Argument "b" isn't numeric in addition (+) at foo.pl line 6.
Argument "a" isn't numeric in addition (+) at foo.pl line 6.
0
Argument "a" isn't numeric in addition (+) at foo.pl line 7.
1
a1
3
12

Specifically note that the + operator is not doing any conversion of one type to another - it is a math operator, not a string operator (thats .). Each operation you explicitly identify what type of operation you want to do on the operands.

Java

public static String foo(String a, String b) {
    return a.concat(b);
}
public static void main (String[] args) {
    System.out.println(foo("a",1));
}

Thats a compile error. Changing it to an Integer object rather than an int primitive doesn't help:

public static String foo(String a, String b) {
    return a.concat(b);
}
public static void main (String[] args) {
    System.out.println(foo("a",Integer.valueOf(1)));
}

Thats a compile error too. There is no implicit conversion from Integer or int (or any number format) to a String.

There is however, a shortcut for creating Strings based on the + operator. Apparently, it was decided that the String + ? and ? + String operator should be overloaded to do a string concatenation of the two objects as this was done frequently enough. However this is an example of operator overloading in a single special case rather than implicit conversion from some type to a String. It is also never ambiguous if you are using the + operator on Strings or Numbers. If its all numbers, its a number; if there is a String, its a string (you can't add Objects or Streams).

Additionally, in many places toString() is called on an object to do something with it (debug messages and the like) - but this isn't an implicit change.

VB.NET

Imports System

Public Class Test
    Public Shared Sub Main()
        Console.writeLine(1 + 2)
        Console.writeLine("a" + "b")
        Console.writeLine(1 + "a")
    End Sub
End Class

https://ideone.com/YZTwhX

This produces the output:

3
ab

And has a runtime error:

Unhandled Exception: System.InvalidCastException:
  Conversion from string "a" to type 'Double' is not valid.
  ---> System.FormatException: Unknown char: a

Note that changing the order of 1 + "a" to "a" + 1 gives the same error.

Conclusion

No, other languages don't have implicit conversion from one type to another. Some languages have explicit operands for doing math or string operations, but these are not implicit.

Some languages catch these errors at compile time, others at run time - but in the sample given, they are not valid.

In languages with dynamic typing, it can be rather difficult to understand if you want the String concatenation operator or the math addition operator. Since Ruby uses + for both of these operations, when there is an ambiguous situation, its an error.

The alternative would be to make the operands different (as Perl and Basic do), but Ruby tends to have a culture of overloading operators and thus the design decision that leads to this error. Similar issues will arise with << being used in different contexts (the << operator appends to an array, writes to IO, left shifts a bit, appends to a message digest, or whatever else it has been overloaded to do). This was a design decision to allow this level of mailability in the language - something other languages tend to avoid. It came with the cost of errors when it possible to interpret something two ways (something other languages tend to avoid).


Into the perl magic

There seems to be some confusion with perl's scalar as a string and an number.

From perldata:

Scalars aren't necessarily one thing or another. There's no place to declare a scalar variable to be of type "string", type "number", type "reference", or anything else. Because of the automatic conversion of scalars, operations that return scalars don't need to care (and in fact, cannot care) whether their caller is looking for a string, a number, or a reference. Perl is a contextually polymorphic language whose scalars can be strings, numbers, or references (which includes objects). Although strings and numbers are considered pretty much the same thing for nearly all purposes, references are strongly-typed, uncastable pointers with builtin reference-counting and destructor invocation.

There isn't a conversion of a String to an Integer being done - its just a scalar that is there. Depending on how you want to look at it (which operator you are using), the appropriate part of the scalar is pulled out and used.

A scalar value in perl is a String or a number until its used in a numeric context or a string context. Once it is used in that context, the data structure that is behind the Scalar populates the other value too.

The easiest way to show this is to create a scalar that has radically different values in its parts.

#!/usr/bin/perl

use Scalar::Util qw (dualvar);

$foo = dualvar 42, "Hello";
print $foo + 2,"\n";
print $foo . " world\n";

The output of this is:

44
Hello world

There is no implicit conversion being done here.

You can see the other value being populated when looking at the isdual function:

#!/usr/bin/perl

use Scalar::Util qw (isdual);

$foo = "10";    # A string
$dual = isdual($foo);
print ($dual?"true":"false"); print "\n";
$bar = $foo + 0; # $foo used in numeric context
$dual = isdual($foo);
print ($dual?"true":"false"); print "\n";
print "\n";

$qux = 10;      # A number
$dual = isdual($qux);
print ($dual?"true":"false"); print "\n";
$bar = $qux . "foo";    # $qux used in a string context
$dual = isdual($qux);
print ($dual?"true":"false"); print "\n";

The output of this is:

false
true

false
true

The value starts out as one thing, and as it is used in the given context the other half of the scalar is populated. However, each of these is an explicit conversion when it is used in that context.

It should be noted that my VBA example above is incomplete. The & operator is the String concatenation in many Basic dialects. Larry Wall started out as a Basic programmer and was undoubtedly influenced by its approach to handling string and math operators as separate things rather than trying to mix them together.

Licensed under: CC-BY-SA with attribution
scroll top