Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
770 views
in Technique[技术] by (71.8m points)

scala - toList on Range with suffix notation causes type mismatch

I am just starting with Scala, and trying out some things on Range and List, I get something very strange with a very simple snippet. I use sublime to edit and execute these snippets:

val a = 1 to 10
println(a)

yields

Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

while

val a = 1 to 10
val b = a toList
println(a)

gives me the error:

/home/olivier/Dropbox/Projects/ProjectEuler/misc/scala/ch05_ex02.scala:5:     error: type mismatch;
 found   : Unit
 required: Int
println(a)
       ^
one error found

In the REPL, on the contrary, I do not get any error. Scala version is 2.9.2

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This is caused by the way the compiler parses Suffix Notation (for methods of arity 0). It will try to parse it as Infix Notation (if possible). This causes the compiler to parse your code like this:

val a = 1 to 10
val b = a toList println(a)

Or specifically the latter line with dot notation:

val b = a.toList.apply(println(a))

List[A] has an apply method taking varargs of type A (in this case, an Int) and println returns Unit. That's the reason for this specific error message.

This style is frowned upon as specified in the Scala Documentation:

Suffix Notation

Scala allows methods of arity-0 to be invoked using suffix notation:

names.toList
// is the same as
names toList // Unsafe, don't use!

This style is unsafe, and should not be used. Since semicolons are optional, the compiler will attempt to treat it as an infix method if it can, potentially taking a term from the next line.

names toList
val answer = 42   // will not compile!

This may result in unexpected compile errors at best, and happily compiled faulty code at worst. Although the syntax is used by some DSLs, it should be considered deprecated, and avoided.

As of Scala 2.10, using suffix operator notation will result in a compiler warning.

As recommended, use the dot notation:

val b = a.toList

Or if you really want to, add a semicolon to denote the end of line:

val b = a toList;

Note the latter will emit a compiler warning, as stated in the docs:

[warn] postfix operator toList should be enabled
[warn] by making the implicit value scala.language.postfixOps visible.
[warn] This can be achieved by adding the import clause 'import scala.language.postfixOps'
[warn] or by setting the compiler option -language:postfixOps.
[warn] See the Scaladoc for value scala.language.postfixOps for a discussion
[warn] why the feature should be explicitly enabled.
[warn]   val b = a toList;
[warn]             ^
[warn] one warning found

In the REPL, on the contrary, I do not get any error.

Because the REPL executes on a line by line basis. As the toList expression isn't succeeded by the println expression, it compiles. If you enter paste mode (:paste) and copy it as a block of code, you'll see the same behavior.

More info can be found in this Scala user-group question


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...