There is a note in Cay Horstmann's book "Scala for the Impatient" about the apply method:
Occasionally, the () notation conflicts with another Scala feature: implicit parameters. For example, the expression
"Bonjour".sorted(3)
yields an error because the sorted method can optionally be called with an ordering, but 3 is not a valid ordering.
The solution is to assign "Bonjour".sorted
to a variable and call apply on it, for example:
val result = "Bonjour".sorted
result(3)
Or call apply explicitly:
"Bonjour".sorted.apply(3)
But why this doesn't work and produces a compile error:
("Bonjour".sorted)(3)
The sorted method returns a String
, which can be imlicitly converted to a StringOps
and parentheses are used to wrap the string expression. Why compiler doesn't accept to call the apply method of a StringOps
?
You can use -Xprint:parser
to see that the parens are discarded early:
scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x
scala> "hi".scaled(5)
res0: String = hihihihihi
scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi
scala> "hi".scaled(5)(3)
res2: Char = i
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi
scala> :se -Xprint:parser
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of parser]] // <console>
package $line8 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.x;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res4 = {
implicit val n: Int = 5;
"hi".scaled(3)
}
}
}
}
}
res4: String = hihihi
scala>
The extra parens do nothing. The compiler just sees an application expr(args)
. Because it's an application, you don't get "implicit application" conversion.
In any case, the meaning of scaled
, a method, depends on the expected type.
The reason we expect the extra parens to make a difference is that parens override precedence of operators. But (x)
is just x
.
Possibly the spec is actually clear about this:
e(args)
requires that e
be applicable to the args
. In particular, the args are typechecked according to the parameter types of e
.
e(args)
is taken as e.apply(args)
if e
is a value, but scaled
is a method.
You're hoping for "implicit application" to insert the implicit args, but that only applies when e
is not already applied. Or that (e)(args)
could be taken as (e(_))(args)
, that is, (x => e(x))(arg)
.
When written as e.apply(arg)
, the e
is not an application like e(arg)
, so you benefit from conversions like implicit application.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.