1

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?

  • 8
    I hate phrasing it this way... but... "why should it?" And if the answer is "other languages have it" then I'd urge you to write some php. – user40980 May 21 '14 at 2:13
  • I kind of like PHP. It's one of the best documented languages along with Java. Ruby is one of the worst documented, along with VBA. Implicit number conversion for string concatenation: ideone.com/BCfzPe – Chloe May 21 '14 at 5:18
10

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"
  • 4
    There's also "a"+1.to_s if you really want to use the + operator, though thats no longer implicit. – user40980 May 21 '14 at 3:20
  • Java has strong typing, but it also has implicit conversions. I don't think Ruby has strong typing, because it uses dynamic typing. Perl and PHP have string interpolation, plus they have implicit conversion. Do you think there is a Ruby phrase which is unparsable if it allowed implicit conversion? – Chloe May 21 '14 at 5:23
  • 2
    @Chloe I should point out that perl doesn't have implicit to string. print "a" + 1; in perl prints 1 because + is a math operator rather than a string operator. Meanwhile, print 1 . 2; in perl prints 12 because . is the string concatenation operator. These are very explicit operators, no implicit conversion at all. – user40980 May 21 '14 at 5:37
  • 6
    @Chloe, note that a language can be both dynamic and strongly typed at the same time, and your example actually proves that. If Ruby were weakly typed, you wouldn't be getting a type error. – Karl Bielefeldt May 21 '14 at 5:46
  • @MichaelT Perl uses . for string concatenation, same as PHP. You would use print 'a'.1; – Chloe May 21 '14 at 22:36
3

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.

  • Perl does have conversion from number to string, plus it also has implicit conversion from string to number. See the 3rd example you provide for number to string: print "a".1;. An example of implicit conversion from string to number: $ perl -e 'print "1"+1' yields 2. BTW the string concatenation operator in VBA is &: ideone.com/bGYDOz – Chloe May 21 '14 at 22:42
  • 1
    @Chloe: Note how in both cases, you know (and specify) whether to treat the values as strings or as numbers. Ruby can't do that without issues, because it decided to use the same operator for concatenation and addition. How is it supposed to know whether "1" + 1 should be 2 or '11'? – cHao May 21 '14 at 22:58
  • 1
    @Chloe Larry Wall was strongly influenced by Basic in in the early days of creating Perl. It is no surprise that he would take the approach of having two different operators for two different contexts. The thing is when you have one operator for multiple contexts and try to mix them together you will have the situation where there are multiple, correct parsings. Ruby made that design decision and throws an error when that situation arises. Other languages try to make it so that such a situation cannot arise in the first place - this can be done with multiple operators for different things. – user40980 May 22 '14 at 17:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.