Universal Apply Methods
Scala case classes generate apply methods, so that values of case classes can be created using simple function application, without needing to write
Scala 3 generalizes this scheme to all concrete classes. Example:
class StringBuilder(s: String): def this() = this("") StringBuilder("abc") // old: new StringBuilder("abc") StringBuilder() // old: new StringBuilder()
This works since a companion object with two
apply methods is generated together with the class. The object looks like this:
object StringBuilder: inline def apply(s: String): StringBuilder = new StringBuilder(s) inline def apply(): StringBuilder = new StringBuilder()
The synthetic object
StringBuilder and its
apply methods are called constructor proxies. Constructor proxies are generated even for Java classes and classes coming from Scala 2. The precise rules are as follows:
A constructor proxy companion object
object Cis created for a concrete class
C, provided the class does not have already a companion, and there is also no other value or method named
Cdefined or inherited in the scope where
applymethods are generated for a concrete class provided
- the class has a companion object (which might have been generated in step 1), and
- that companion object does not already define a member named
applymethod forwards to one constructor of the class. It has the same type and value parameters as the constructor.
Constructor proxy companions cannot be used as values by themselves. A proxy companion object must be selected with
apply (or be applied to arguments, in which case the
apply is implicitly inserted).
Constructor proxies are also not allowed to shadow normal definitions. That is, an ambiguity is reported, if
- an identifier resolves to a constructor proxy,
- the same identifier is also defined or imported in some other scope,
- the other reference can be applied to a (possibly empty) parameter list. That is, it refers either to a method or to a value containing an apply method as member.
new hides an implementation detail and makes code more pleasant to read. Even though it requires a new rule, it will likely increase the perceived regularity of the language, since case classes already provide function call creation syntax (and are often defined for this reason alone).