The Scala API. Scala has a reputation of being a difficult language Some people feel that Scala is...
-
Upload
alexandrina-simon -
Category
Documents
-
view
228 -
download
1
Transcript of The Scala API. Scala has a reputation of being a difficult language Some people feel that Scala is...
The Scala API
The Scala API
Scala has a reputation of being a difficult language Some people feel that Scala is beyond what the average
programmer can master Others say it’s no more difficult than Java
Some things have been added, but a lot has been simplified
Everyone agrees that the Scala API is harder to understand than the Java API This certainly makes Scala seem more difficult than it is You don’t have to understand everything about a method in
order to use it effectively This lecture is an attempt to de-mystify the Scala API
2
Searching
The API is search oriented; every frame has a search field You can click on a letter and search for methods
3
Icons
C indicates a class T indicates a trait O indicates an object O and C together indicate a
class with a companion object
4
Objects
A class is a template for creating objects But if you need only one object of a given type, you can just
create it directly object Instructor { val name = "David Matuszek" }
Scala provides a number of predefined objects, such as Console
object TryIt { def main(args: Array[String]): Unit = { val c = Console c.print("Hello, console!") }}
Hello, console!
5
Classes
A class is a template for creating objects; it may take parameters Classes may be marked as case, abstract, or final
case classes have special features To create an object, you may omit the word new Case classes can be used in pattern matching Case classes have automatically generated toString, hashCode, and equals methods (which use the constructor parameters)
abstract classes cannot be instantiated final classes cannot be subclassed
6
Creating new objects from classes When you define a class, you usually use the word new to create objects of that class
object TryIt { def main(args: Array[String]): Unit = { val t = new Thing(1) }}class Thing(number: Int) { println(s"I'm Thing $number!")}
If you make the class a case class, you don’t need the word new object TryIt {
def main(args: Array[String]): Unit = { val t = Thing(1) }}case class Thing(number: Int) { println(s"I'm Thing $number!")}
Both objects produce this output: I'm Thing 1!
7
Companion objects and classes If a class and an object have the same name and are defined on the same source
file, they are companions Each has access to all the features of the other
object Thing { private var count = 0 def main(args: Array[String]): Unit = { new Thing(1, 2, 3) println(s"That's $count Things!") }}class Thing(val numbers: Int*) { for (n <- numbers) { println(s"I'm Thing $n!") Thing.count += 1 }}
I'm Thing 1!I'm Thing 2!I'm Thing 3!That's 3 Things!
8
Companion objects and static Values and methods in a companion object are similar to static values and methods in Java
The companion object is often a good place to put factory methods
object Thing { def main(args: Array[String]): Unit = { val t = thingMaker(5) println(t) } def thingMaker(n: Int) = new Thing(n)}case class Thing(val number: Int)
Thing(5)
9
The apply method The apply method of a companion object typically creates an object of the
companion class scala> val nums = List.apply(1, 2, 3, 4, 5)
nums: List[Int] = List(1, 2, 3, 4, 5) scala> val m = Map.apply(1 -> 10, 2 -> 20)
m: scala.collection.immutable.Map[Int,Int] = Map(1 -> 10, 2 -> 20)
The apply method of an object typically indexes into that object scala> m.apply(2)
res10: Int = 20 scala> nums.apply(2)
res9: Int = 3
thing(arg) gets translated into thing.apply(arg) A case class has an apply method; this is why you don’t need new
10
Traits
A trait is like a Java interface, except that it can have concrete as well as abstract methods
Traits can be “mixed in” to classes and objects trait Stretchable { def stretch(s: String) = s.toList.mkString(" ")}object Thing extends Stretchable { def main(args: Array[String]) { val hi = "Hello, World!" println(stretch(hi)) }}
H e l l o , W o r l d !
11
Int is in the scala package It is abstract, so you can’t directly create an Int It is final, so you can’t create a subclass of Int It extends AnyVal, which is the superclass of values
that in Java are “primitives” AnyVal extends Any, which is the “topmost” class AnyRef also extends Any, and is the class that corresponds to
Java’s Object class
12
Operators are methods
Unlike Java, operators are methods This means that they are all in the Scala API
In Scala, a name can be: Composed of letters, digits, and underscores Composed of “punctuation marks,” excluding brackets and periods Composed of letters, digits, and underscores, then an underscore, then
punctuation marks Composed of just about anything (even whitespace) enclosed in backquotes
For example, in the description of Any: final def ==(arg0: Any): Boolean
Test two objects for equality. The expression x == that is equivalent to if (x eq null) that eq null else x.equals(that).
returns true if the receiver object is equivalent to the argument; false otherwise.
13
Parameters and return values scala> class Animal
defined class Animal
scala> class Mammal extends Animaldefined class Mammal
scala> class Dog extends Mammaldefined class Dog
scala> object Tester { | def identity(m: Mammal): Mammal = m | def test = { | val something: Animal = identity(new Dog) | something | } }defined module Tester
scala> Tester.testres2: Animal = Dog@563625d0
14
Function1 Function1 is declared in the Scala API as
trait Function1[-T1, +R] extends AnyRef The –T1 indicates that the parameter may be a supertype (this is contravariance) The +R indicates that the return value may be a subtype (this is covariance) Functions are contravariant in their argument types and co-variant in their return types class Animal
class Dog extends Animalclass Personclass Student extends Person
def owner(f: Dog => Person) { println("ok") }
def dogOwner(d: Dog) = new Person // exactly as expecteddef petOwner(d: Dog) = new Student // return is subtypedef animalOwner(a: Animal) = new Person // arg is supertype
The following calls are all legal, and all print ok: owner(dogOwner) owner(petOwner) owner(animalOwner)
15
Contravariance in parameters
On the previous slide, Dog extends Animal and Student extends Person
We also had the definitions: def owner(f: Dog => Person) { println("ok") }
The argument to this function has type Dog => Person def dogOwner(d: Dog) = new Person This is a function of exactly the type required, so it works def petOwner(d: Dog) = new Student
This is a function Dog => Student, but Student is a subclass of Person, so it works (covariance)
def animalOwner(a: Animal) = new Person This is a function Animal => Person, but Animal is a superclass of Dog Since this function will take any Animal as a parameter, it will work for a Dog (this is contravariance), and we can use it as a parameter to owner
16
Java isn’t type safe class Animal {}
class Mammal extends Animal {}
public class Animals { public static void main(String[] args) { Mammal[] mammals = new Mammal[1]; Animal[] animals = mammals; animals[0] = new Animal(); System.out.println(animals[0]); }}
This compiles without any problem Exception in thread "main"
java.lang.ArrayStoreException: Animalat Animals.main(Animals.java:9)
17
Covariance, contravariance, invariance
Covariance and contravariance are properties of collections A collection of values of type A is covariant if it may be treated as
a collection of values of some supertype of A That is, you can use a subtype of the expected type Lists are covariant because a List[Dog] may be treated as if it were a List[Animal]
class List [+A] extends LinearSeq[A] A collection of values of type A is contravariant if it may be treated
as a collection of values of some subtype of A That is, you can use a supertype of the expected type trait Function1 [-T1, +R] extends AnyRef This trait defines a function that is contravariant in its argument type, and
covariant in its return type
A collection is invariant if it is neither covariant or contravariant18
Again, with pictures
19
Suppose you have a function of type B → C
B → C
And suppose you would like to give the function a value of type A, and get back a value of type D
A → → D
You can do this if A is a subtype of B, and C is a subtype of D
D
A
Again, with pictures
20
Suppose you have a function of type B → C
B → C
And suppose you would like to give the function a value of type A, and get back a value of type D
A → → D
You can do this if A is a subtype of B, and C is a subtype of D
Variance for mutable structures For type safety
Read-only (source) data structures can be covariant Write-only data types (sinks) can be contravariant If a data structure is both readable and writeable (such as arrays in Java), it
should be invariant Java arrays are covariant
Did Java get it wrong? If arrays were invariant, generic operations that do not depend on the type of
object (shuffling an array, comparing two arrays for equality) would not be possible
Generics (parameterized types) make a solution possible, but not without breaking legacy programs
<T> boolean equalArrays (T[] a1, T[] a2); Unlike Java, Scala has had parameterized types from the beginning
Scala does not infer variance types; that’s up to the programmer
21
Multiple parameter lists def foldLeft [B] (z: B)(op: (B, A) ⇒ B): B
A and B are type parameters z is of type B op is a function that takes a B and an A and returns a B scala> List(1, 2, 3).foldLeft(10.0)(_ + _)
res15: Double = 16.0 The parameter lists allow partial application of the function to create another
function scala> val fold10 = (_: List[Int]).foldLeft(10.0)(_
+ _)fold10: List[Int] => Double = <function1>
Here we are supplying an indefinite receiver and an indefinite final argument (underscores)
scala> fold10(List(1, 2, 3))res26: Double = 16.0
22
Least Upper Bound
The notation B >: A states that B is a superclass of A
All the elements of a List must be of the “same type.” The “cons” operator, ::, is defined in List asdef :: (x: A): List[A] Consing a value of type A to a List[A] returns a List[A] But there is an additional definition,def :: [B >: A] (x: B): List[B]
If B is a superclass of A, B >: A, then adding a B to a List[A] will result in a List[B]
23
Sir With-A-Lot
Scala objects are usually built from small pieces Lots of inheritance, lots of “withing” The above are buttons, allowing you to control how much is displayed
Anything, such as List above, that inherits from Seq (sequence) or TraversableLike, will supply the important functions map, flatMap, filter, and probably some folds
24
Use the source, Luke
Although the documentation is often difficult to understand, the source code often is not
Scala methods tend to be short The high-level constructs often make code easier to read
Just as Java has javadoc for producing professional-looking documentation, Scala has scaladoc
As your code does not have the same constraints as library code, your scaladoc files will probably not be this complicated
25
26
The End