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.