1 Flashcards
How do Scala traits differ from Java interfaces?
Scala traits can be viewed as Java interfaces with extended capabilities, so to speak:
- An interface can only define abstract methods, while traits can immediately provide an implementation.
- An interface cannot define fields, whereas a trait can
An interface simply provides a prescription that an implementer must meet, while a trait can actually add, or “mix in” reusable pieces consisting of components for behavior and state
Give an example of the Family Polymorphism problem.
Family polymorphism is a generalized version of polymorphism that allows static declaration and management of relationships between multiple classes in a polymorphic way. This can be seen as considering a group of classes as a family, where relations exist between its members, without statically knowing which classes are which. (Static = at compile time)
An example would be an XYList containing inner classes XList and YList where the XList has as head an X and as tail a YList and vice versa (= mutual recursion). So there is clearly a relationship between the group of classes.
If we now create a subfamily of this group of classes, it means that we create a class XYListWithLen that inherits from XYList and in turn inner classes XListWithLen and YListWithLen with a similar interrelationship as the superfamily (but between XListWithLen and YListWithLen) and here the additional functionality to define the length of the lists.
What Scala feature enables a clean solution to the family polymorphism problem?
A clean solution to this problem is possible thanks to abstract type members. The family members are defined as abstract types (with the upper bound that xList must be a subtype of XList and yList of YList) after which this abstract type is used everywhere in the classes instead of XList and YList.
Each subfamily then further constrains these abstract types itself or concretizes them. So for our subfamily of XYListWithLen, XListWithLen and YListWithLen, xList will have an upper bound so that it is a subtype of XListWithLen and yList will have an upper bound so that it is a subtype of YListWithLen.
This approach is type safe (among other things, explicit downcasts are avoided in the code that could lead to ClassCastExceptions at runtime).
How can a trait express constraints on the contexts in which it will be mixed?
A trait can contain abstract types with lower and upper bounds so that any context in which it is mixed is required to adhere to these bounds when concretizing or extending.
In addition, traits can also contain self types. This establishes a dependency to another class or trait.
Anything that extends the trait must also extend a subtype of the self type or the self type itself. So this is an additional type dependency imposed by the trait on its context class in which it is mixed.
What are the criteria for a good solution to the Expression Problem?
The Expression problem is a 2-dimensional problem formulated by Wadler:
* A data type is defined by a set of data variants
* There are processors that perform an operation on this data type
A good solution to this problem meets the following requirements:
* Expandability in both dimensions:
o Adding new data variants is possible (E.g. Arithmetic expressions)
o Adding new processors is possible (E.g. Evaluation, pretty printing in prefix notation)
* Strong static type safety:
o It is impossible to apply a processor to a data variant that is unsupported
* Existing code should not be modified or duplicated
* Separated compilation
o Type checking of existing code need not be done for compilation of additions
* Independent extensibility = Additional requirement, later added by Odersky and Zheng:
o It is possible to combine separately developed additions