Traits
Similar tointerfaces in Java
They may have implementations of methods
But can’t contain state
Can be multiply inherited from
2.
Example of traits
traitSimilarity {
def isSimilar(x: Any): Boolean;
def isNotSimilar(x: Any): Boolean = !isSimilar(x);
}
class Point(xc: Int, yc: Int) with Similarity {
var x: Int = xc;
var y: Int = yc;
def isSimilar(obj: Any) =
obj.isInstanceOf[Point] &&
obj.asInstanceOf[Point].x == x;
}
3.
Mixin class composition
Basic inheritance model is single inheritance
But mixin classes allow more flexibility
class Point2D(xc: Int, yc: Int) {
val x = xc;
val y = yc;
// methods for manipulating Point2Ds
}
class ColoredPoint2D(u: Int, v: Int, c: String)
extends Point2D(u, v) {
var color = c;
def setColor(newCol: String): Unit = color = newCol;
}
4.
Mixin class compositionexample
ColoredPoint2D
Point2D
class Point3D(xc: Int, yc: Int, zc: Int)
extends Point2D(xc, yc) {
val z = zc;
// code for manipulating Point3Ds
}
Point3D
class ColoredPoint3D(xc: Int, yc: Int, zc: Int, col: String)
extends Point3D(xc, yc, zc)
with ColoredPoint2D(xc, yc, col);
ColoredPoint3D
ColoredPoint2D
5.
Mixin class composition
Mixin composition adds members explicitly
defined in ColoredPoint2D
(members that weren’t inherited)
Mixing a class C into another class D is legal
only as long as D’s superclass is a subclass of
C’s superclass.
i.e., D must inherit at least everything that C
inherited
Why?
6.
Mixin class composition
Remember that only members explicitly
defined in ColoredPoint2D are mixin
inherited
So, if those members refer to definitions
that were inherited from Point2D, they had
better exist in ColoredPoint3D
They do, since
ColoredPoint3D extends Point3D
which extends Point2D
7.
Views
Defines acoercion from one type to another
Similar to conversion operators in C++/C#
trait Set {
def include(x: int): Set;
def contains(x: int): boolean
}
def view(list: List) : Set = new Set {
def include(x: int): Set = x prepend xs;
def contains(x: int): boolean =
!isEmpty &&
(list.head == x || list.tail contains x)
}
8.
Views
Views areinserted automatically by the Scala
compiler
If e is of type T then a view is applied to e if:
expected type of e is not T (or a supertype)
a member selected from e is not a member of T
Compiler uses only views in scope
Suppose xs : List and view above is in scope
val s: Set = xs;
xs contains x
val s: Set = view(xs);
view(xs) contains x
Compound types
InJava, the “solution” is:
interface CloneableAndResetable extends
Cloneable, Resetable
But if the original object did not use the
CloneableAndResetable interface, it won’t
work
Scala solution: use compound types (also
called intersection types)
def cloneAndReset(obj: Cloneable with Resetable):
Cloneable = {
...
}
11.
Variance annotations
class Array[a]{
def get(index: int): a
def set(index: int, elem: a): unit;
}
Array[String] is not a subtype of Array[Any]
If it were, we could do this:
val x = new Array[String](1);
val y : Array[Any] = x;
y.set(0, new FooBar());
// just stored a FooBar in a String array!
12.
Variance Annotations
Covarianceis ok with functional data structures
trait GenList[+T] {
def isEmpty: boolean;
def head: T;
def tail: GenList[T]
}
object Empty extends GenList[All] {
def isEmpty: boolean = true;
def head: All = throw new Error("Empty.head");
def tail: List[All] = throw new Error("Empty.tail");
}
class Cons[+T](x: T, xs: GenList[T]) extends GenList[T] {
def isEmpty: boolean = false;
def head: T = x;
def tail: GenList[T] = xs
}
13.
Variance Annotations
Canalso have contravariant type parameters
Useful for an object that can only be written to
Scala checks that variance annotations are
sound
covariant positions: immutable field types,
method results
contravariant: method argument types
Type system ensures that covariant
parameters are only used covariant positions
(similar for contravariant)
14.
Types as members
abstractclass AbsCell {
type T;
val init: T;
private var value: T = init;
def get: T = value;
def set(x: T): unit = { value = x }
}
def createCell : AbsCell {
new AbsCell { type T = int; val init = 1 }
}
Clients of createCell cannot rely on the fact that
T is int, since this information is hidden from them
15.
Discussion/Critiques
Scala hasnominal subtyping. Is this good?
Inheritance and subtyping are conflated in
Scala. Shouldn’t they be separated?
Mixins in MzScheme vs. Scala – MzScheme
allows a class to parameterize its supertype,
while Scala does not
Type system does not distinguish null
references from non-null references
Editor's Notes
#2 Traits can have code, unlike Java interfaces, but can’t have any state associated with them.
Scala allows multiple inheritance of traits
#8 Note that changes to the result returned by ‘view’ are not reflected in the original function.