Description
Scala omits the trait constructor if the template body has only only abstract defs.
This leads to two binary fragilities:
If a trait that was previously a pure interface is recompiled and becomes a regular trait with a constructor, previously compiled subclasses will fail to call the constructor.
Conversely, if a previously regular trait becomes pure, previously compiled subclasses will incur a linkage error calling the now-absent constructor:
https://gist.github.com/af3037454509de9412fc8e1d5d38d43c
The absense/presence of this constructor is now relied upon for choice of whether a SAM can be encoded with LambdaMetafactory
or whether to use an AOT compiled anonymous class. Orthogonal to the binary fragilities above, this has the problem of being too restrictive: e.g. scala.PartialOrdering
is ineligible for SAM treatment.
Dotty has an extra flag HasInits
that tracks the more specific information about constructor side effects.
- What was the original rationale behind omitting
T$class
/$init$
for traits that could be classfied asINTERFACE
? - Does this still hold up after changes to the encoding and improvements to
JIT
? - Perhaps it would be better to unconditionally emit the constructor now, and give users an annotation
@noconstructor
that enforced no statements in the trait.