Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala String toInt - Int does not take parameters

So I'm learning Scala and I came across this finicky issue...

If we have a String and want to convert it to an Int, all examples that I've found online say, "It's so simple! Just use String.toInt!"

Okay:

var x = readLine().toInt

Simple enough. I'm assuming toInt is a function of String. But if that's the case, I should be able to call toInt with parentheses, right? Coming from Java, this feels more natural to me:

var x = readLine().toInt()

But alas! Scala gives me the following error:

[error] /home/myhome/code/whatever/hello.scala:13: Int does not take parameters

[error] var x = readLine().toInt()

Curious. What does this error mean? Is toInt not a function of String? Similarly, why can I do both:

var x = readLine().toLowerCase()
var y = readLine().toLowerCase

with out any problems?

Edit: The duplicate question does not address the toLowerCase vs toInt issue.

like image 718
Kenny Worden Avatar asked Feb 18 '17 20:02

Kenny Worden


People also ask

How do I convert a string to an int in Scala?

A string can be converted to integer in Scala using the toInt method. This will return the integer conversion of the string. If the string does not contain an integer it will throw an exception with will be NumberFormatException. So, the statement: val i = "Hello".

How do you convert int to Scala?

Scala Char toInt() method with example The toInt() method is utilized to convert a stated character into an integer or its ASCII value of type Int. Return Type: It returns Integer or ASCII value of the corresponding character of type Int.


1 Answers

This is a good question, and I don't think it counts as a duplicate of the question about defining zero-arity methods with or without parentheses.

The difference between toInt and toLowerCase here is that toInt is a syntactic enrichment provided by the standard library's StringOps class. You can check this by using reify and showCode in the REPL:

scala> import scala.reflect.runtime.universe.{ reify, showCode }
import scala.reflect.runtime.universe.{reify, showCode}

scala> showCode(reify("1".toInt).tree)
res0: String = Predef.augmentString("1").toInt

This just desugars the enrichment method call and shows you what implicit conversion has been applied to support it.

If we look at the toInt method on StringOps, we see that it's defined without parentheses. As the answer to the possible duplicate question points out, if a zero-arity method in Scala is defined without parentheses, it can't be called with parentheses (although if it's defined with parentheses it can be called either way).

So that's why "1".toInt() doesn't work. If String were a normal Scala class following normal Scala naming conventions, "ABC".toLowerCase() wouldn't work either, since the method would be defined without parentheses, since it's not side-effecting (this is just a convention, but it tends to be pretty consistently applied in Scala code).

The problem is that String isn't actually a class in the Scala standard library—it's just java.lang.String. At the JVM level, there's no difference between a zero-arity method defined with parentheses and one defined without parentheses—this is purely a Scala distinction, and it's not encoded in the JVM method signature, but in a separate batch of metadata stored in the class file.

The Scala language designers decided to treat all zero-arity methods that aren't defined in Scala (and therefore don't have this extra metadata) as if they were defined with parentheses. Since the toLowerCase method on String is really and truly a method of the java.lang.String class (not a syntactic enrichment method like toInt), it falls into this category, which means you can call it either way.

like image 141
Travis Brown Avatar answered Oct 06 '22 01:10

Travis Brown