To make scala.collection.immutable.List
accessible without import
, package object scala
defines both a type alias and “term alias”:
type List[+A] = scala.collection.immutable.List[A] // Transparent
val List = scala.collection.immutable.List // Opaque
This is a commonly used technique – in scala
, scala.Predef
, and in many libraries. So far so good. However, the former alias is de jure, whereas the latter - only de facto. The type
is transparent, the val
is opaque - you shouldn’t look at the right-hand side, and even if you do, there’s no (formal) guarantee that it will stay the same.
This is not a problem for compiling and running the code, but is a problem for editing the code - how an IDE would know that the List
term is actually scala.collection.immutable.List
? And vice versa: if you look for usages of scala.collection.immutable.List
, you probably also want to see usages of List
. We may add heuristics, but that’s hardly elegant.
While we now have both transparent and opaque type alias members (in Scala 3), there’s no way to define a transparent term alias. Although import
s (inlcuding ones with renaming) are transparent (if you navigate to an imported name, you navigate to the defintion, not to the import
statement), they are not members, and so are not “exportable” outside the scope:
import scala.collection.immutable.List // Not exported
export
s are “exportable”, but they are not transparent (?):
package object scala {
export scala.collection.immutable.List // Opaque
}
Interestingly, a val
is effectively transparent if it’s a constant value definition – a final val
without a type annotation and with a constant expression as the RHS. However, constant expressions don’t seem to include object
s (?), which is strange, given how this works in the literal-based singleton types. Even though object
is effectively lazy val
, it’s transparent, because the RHS is synthesized by the compiler.
Can, in principle, the language treat a reference to an object
as a constant expression (at least for top-evel object
s), and the standard library make scala.List
, as well as other wanna-be-transparent term aliases, final
? Then Scala code can have transparent term aliases, which can be correctly handled by IDEs. (The key here is the semantics; whether the compiler replaces LHS with RHS in the bytecode, as it does with literals, is an implementation detail.)