The Scala Programming Language presented by Donna Malayeri
The Scala Programming Language presented by Donna Malayeri
Why a new language? n Goal was to create a language with better support for component software n Two hypotheses: n Programming language for component software should be scalable n n n The same concepts describe small and large parts Rather than adding lots of primitives, focus is on abstraction, composition, and decomposition Language that unifies OOP and functional programming can provide scalable support for components n Adoption is key for testing this hypothesis n Scala interoperates with Java and. NET
Features of Scala n Scala is both functional and object-oriented n every value is an object n every function is a value--including methods n Scala is statically typed n includes a local type inference system: in Java 1. 5: Pair p = new Pair<Integer, String>(1, "Scala"); in Scala: val p = new My. Pair(1, "scala");
More features n Supports lightweight syntax for anonymous functions, higher-order functions, nested functions, currying n ML-style pattern matching n Integration with XML can write XML directly in Scala program n can convert XML DTD into Scala class definitions n n Support for regular expression patterns
Other features n Allows defining new control structures without using macros, and while maintaining static typing n Any function can be used as an infix or postfix operator n Can define methods named +, <= or : :
Automatic Closure Construction n Allows programmers to make their own control structures n Can tag the parameters of methods with the modifier def. n When method is called, the actual def parameters are not evaluated and a noargument function is passed
While loop example object Target. Test 1 with Application { def loop. While(def cond: Boolean)(def body: Unit): Unit = if (cond) { body; Define loop. While method loop. While(cond)(body); } var i = 10; loop. While (i > 0) { Console. println(i); i=i-1 } } Use it with nice syntax
Scala class hierarchy
Scala object system n Class-based n Single inheritance n Can define singleton objects easily n Subtyping is nominal n Traits, compound types, and views allow for more flexibility
Classes and Objects trait Nat; object Zero extends Nat { def is. Zero: boolean = true; def pred: Nat = throw new Error("Zero. pred"); } class Succ(n: Nat) extends Nat { def is. Zero: boolean = false; def pred: Nat = n; }
Traits n Similar to interfaces in Java n They may have implementations of methods n But can’t contain state n Can be multiply inherited from
Example of traits trait Similarity { def is. Similar(x: Any): Boolean; def is. Not. Similar(x: Any): Boolean = !is. Similar(x); } class Point(xc: Int, yc: Int) with Similarity { var x: Int = xc; var y: Int = yc; def is. Similar(obj: Any) = obj. is. Instance. Of[Point] && obj. as. Instance. Of[Point]. x == x; }
Mixin class composition n Basic inheritance model is single inheritance n But mixin classes allow more flexibility class Point 2 D(xc: Int, yc: Int) { val x = xc; val y = yc; // methods for manipulating Point 2 Ds } class Colored. Point 2 D(u: Int, v: Int, c: String) extends Point 2 D(u, v) { var color = c; def set. Color(new. Col: String): Unit = color = new. Col; }
Mixin class composition example Point 2 D Colored. Point 2 D Point 3 D Colored. Point 2 D class Point 3 D(xc: Int, yc: Int, zc: Int) extends Point 2 D(xc, yc) { val z = zc; // code for manipulating Point 3 Ds } class Colored. Point 3 D(xc: Int, yc: Int, zc: Int, col: String) extends Point 3 D(xc, yc, zc) with Colored. Point 2 D(xc, yc, col);
Mixin class composition n Mixin composition adds members explicitly defined in Colored. Point 2 D (members that weren’t inherited) n Mixing a class C into another class D is legal only as long as D’s superclass is a subclass of C’s superclass. n i. e. , D must inherit at least everything that C inherited n Why?
Mixin class composition n Remember that only members explicitly defined in Colored. Point 2 D are mixin inherited n So, if those members refer to definitions that were inherited from Point 2 D, they had better exist in Colored. Point 3 D n They do, since Colored. Point 3 D extends Point 3 D which extends Point 2 D
Views n Defines a coercion from one type to another n 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 = !is. Empty && (list. head == x || list. tail contains x) }
Views n Views are inserted automatically by the Scala compiler n If e is of type T then a view is applied to e if: n expected type of e is not T (or a supertype) n a member selected from e is not a member of T n 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 motivation trait Cloneable { def clone(); } trait Resetable { def reset: Unit; } def clone. And. Reset(obj: ? ): Cloneable = { val cloned = obj. clone(); obj. reset; cloned }
Compound types 1. In Java, the “solution” is: interface Cloneable. And. Resetable extends Cloneable, Resetable 2. But if the original object did not use the Cloneable. And. Resetable interface, it won’t work 3. Scala solution: use compound types (also called intersection types) def clone. And. Reset(obj: Cloneable with Resetable): Cloneable = {. . . }
Variance annotations class Array[a] { def get(index: int): a def set(index: int, elem: a): unit; } n Array[String] is not a subtype of Array[Any] n If it were, we could do this: val x = new Array[String](1); val y : Array[Any] = x; y. set(0, new Foo. Bar()); // just stored a Foo. Bar in a String array!
Variance Annotations n Covariance is ok with functional data structures trait Gen. List[+T] { def is. Empty: boolean; def head: T; def tail: Gen. List[T] } object Empty extends Gen. List[All] { def is. Empty: 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: Gen. List[T]) extends Gen. List[T] { def is. Empty: boolean = false; def head: T = x; def tail: Gen. List[T] = xs }
Variance Annotations n Can also have contravariant type parameters n Useful for an object that can only be written to n Scala checks that variance annotations are sound covariant positions: immutable field types, method results n contravariant: method argument types n Type system ensures that covariant parameters are only used covariant positions (similar for contravariant) n
Types as members abstract class Abs. Cell { type T; val init: T; private var value: T = init; def get: T = value; def set(x: T): unit = { value = x } } def create. Cell : Abs. Cell { new Abs. Cell { type T = int; val init = 1 } } n Clients of create. Cell cannot rely on the fact that T is int, since this information is hidden from them
Discussion/Critiques n Scala has nominal subtyping. Is this good? n Inheritance and subtyping are conflated in Scala. Shouldn’t they be separated? n Mixins in Mz. Scheme vs. Scala – Mz. Scheme allows a class to parameterize its supertype, while Scala does not n Type system does not distinguish null references from non-null references
- Slides: 25