Motivating Scala Package Objects
You can even go even further: why are there packages at all when we have object
s?
Scala is intended to be used as a "hosted language", that is, a language that can reproduce well on another language platform. The original implementations of Scala were in the Java platform and the Common Language Infrastructure platform (or rather, its main implementations, .NET and Mono). Today we also have an implementation on the ECMAScript platform (Scala.js), and the Java platform implementation can also be used on Android, for example. You can imagine other interesting platforms that you would like to run Scala on, for example. Windows UWP platform, Swift / Objective-C / Core Foundation / macOS / iOS / tvOS / watchOS platform, Gnome / GObject platform, Qt / C ++ platform, etc.
Scala not only intends to run on these platforms, it intends to accomplish two often conflicting goals:
- high performance
- tight integration with the "native" feeling.
So in Scala, implementation problems are part of the design of the language. (Rich Hickey, a Clojure developer, once said in a conversation "The JVM is not an implementation detail," the same applies to Scala.) Correct tail calls are a good example: To support correct tail calls, Scala would have to manage its own stack. rather than using the native call stack on the host platform on platforms such as the JVM, which however means you can no longer easily call Scala code from other code on the platform and vice versa. So while correct tail calls would be fine, Scala settles for less strong proper direct tail recursion.
Theoretically only requires Scala object
s, trait
s, techniques, type
s, and the path ( .
and #
). Anything else basically just makes it easier to integrate with the host platform. This includes, for example null
, class
es and package
s.
Ideally, it should be easy to map host platform constructs to Scala constructs and vice versa. So, for example, there is an easy mapping between Scala methods and JVM methods. There is a simple mapping between JVM interfaces and Scala traits with only abstract elements. There is no easy mapping between Scala traits and JVM classes, so Scala has a (redundant) concept of classes. Likewise, there is no simple mapping between Scala object
and the JVM package
(or CLI namespace
s), so Scala has a (redundant) concept package
.
However, we would really like it package
(which are, after all, somewhat similar to Scala object
s) to have members. But the JVM package
and CLI namespace
cannot have members other than interface
and class
es, and since we only introduced them into Scala for compatibility with the host platform, it just doesn't make sense to make them incompatible with the host platform by adding members to them.
So, we introduce another separate concept package object
that contains elements that we would like to add to package
, but cannot, due to compatibility with the host platform.
TL; DR :
- we have
package
because of interaction (although we already haveobject
s that can do all the same things aspackage
s) - we would like to
package
have members -
package
cannot have members because interop - So, we have
package object
as companions forpackage
s
source to share