// ok
val sam0: MySamWithEmptyParameter = () => 100
// doesn't work
// val sam1: MySamWithParameterless = () => 100
trait MySamWithEmptyParameter {
def receive(): Int
}
trait MySamWithParameterless {
def receive: Int
}
Why sam1 fails to override the receive method? The scalac compile both of traits to same code.
abstract trait TestSAM$MySamWithEmptyParameter extends Object {
def receive(): Int
};
abstract trait TestSAM$MySamWithParameterless extends Object {
def receive(): Int
};
SI-10555 talks exactly about this. This was a simple design decision to only support an explicit empty parameter list, even though the two compile down to an empty parameter list anyway.
The relevant part of the Specification says (emphasis mine):
- the method m must have a single argument list;
This is indeed a bit awkward as eta expansion does work for methods with an empty parameter list.
Contacted the guys at Lightbend. Here is a response by Adrian Moors, Scala team lead:
The original reason was to keep the spec simple, but perhaps we should revisit. I agree it’s surprising that it works for
def a(): Int, but not in your example.Internally, methods that don’t define an argument list at all, and those that do (even if empty) are treated differently. This has led to confusion/bugs before — to name just one: https://github.com/scala/scala-dev/issues/284.
In 2.13, we’re reworking eta-expansion (it will apply more aggressively, but ()-insertion will happen first). We’ve been back and forth on this, but the current thinking is:
- 0-ary methods are treated specially: if the expected type is sam-equivalent to Function0, we eta-expand; otherwise,
()is inserted (in dotty, you are required to write the () explicitly, unless the method is java-defined) — I’m still not sure about whether we should ever eta-expand here- for all other arities, a method reference is eta-expanded regardless of the expected type (if there’s no type mismatch, this could hide errors when you refactor a method to take arguments, but forget to apply them everywhere. However, since functions are first-class values, it should be easy to construct them by simplify referring to a method value).
The upshot is that we can deprecate method value syntax (
m _), since it’s subsumed by simply writingm. (Note that this is distinct from placeholder syntax, as inm(, _).) (See also the thread around this comment: https://github.com/lampepfl/dotty/issues/2570#issuecomment-306202339)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With