Last active
December 30, 2015 08:39
-
-
Save petekneller/7803974 to your computer and use it in GitHub Desktop.
Some exploration of the problem Dan Bodart found and discussed in http://dan.bodar.com/2013/12/04/wat-scala/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package gotchas | |
object NoArgMethods { | |
val l = List(1, 2, 3) | |
val correct = l.toSet // has type Set[Int] | |
val wrong = l.toSet() // has type Boolean | |
// toSet() is converted to toSet.apply() | |
// (no surprise there) | |
// what is surprising is that toSet.apply() compiles! | |
// apply on toSet is a unary method, what happens when its applied with 0 args? | |
// looks like the compiler is creating a call with unit | |
val s = l.toSet | |
// fully expanded | |
// ------------------- | |
val s1 = l.toSet.apply() // why does this compile? | |
//val s2 = s.apply() // fails with 'not enough arguments' | |
val s3 = l.toSet apply () // can see that this might be ambiguous; see below | |
//val s4 = s apply () // fails with 'not enough arguments' | |
// partially expanded | |
// ------------------- | |
val s5 = l.toSet.apply () // can see that this might be ambiguous; see below | |
//val s6 = s.apply () // fails with 'not enough arguments' | |
//val s7 = l.toSet.apply // fails with 'Missing arguments' | |
//val s8 = s.apply // fails with 'Missing arguments' | |
// ^ Good. The wouldn't expect the compiler to ever infer a missing arg | |
val s9 = l.toSet apply() // why does this compile? | |
//val s10 = s apply() // fails with 'not enough arguments' | |
//val s11 = l.toSet apply // fails with 'Missing arguments' | |
//val s12 = s apply // fails with 'Missing arguments' | |
// ^ Good. The wouldn't expect the compiler to ever infer a missing arg | |
// The problem never occurs when empty apply call is made against a val/var of the correct type, it only occurs | |
// when made against an intermediate object. Why? | |
// I can sort of see the ambiguity where you're calling foo(Int) like | |
// foo () | |
// is that meant to be interpreted as: | |
// foo() (called with no args) | |
// or | |
// foo(()) (called with one arg of unit type) | |
// After speaking to Dan B, the problem becomes deeper - the inferred type of the intermediate Set is Set[Any], | |
// so we're asking the set if unit is a member | |
val sa: Set[Any] = l.toSet // remove the type annotation and the below line fails to compile (as the previous example of the same shape) | |
val sa1 = sa() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment