Presentation is loading. Please wait.

Presentation is loading. Please wait.

The Scala API.

Similar presentations


Presentation on theme: "The Scala API."— Presentation transcript:

1 The Scala API

2 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

3 Searching The API is search oriented; every frame has a search field
You can click on a letter and search for methods

4 Icons C indicates a class T indicates a trait O indicates an object
O and C together indicate a class with a companion object

5 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!

6 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

7 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!

8 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!

9 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)

10 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

11 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 !

12 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

13 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.

14 Parameters and return values
scala> class Animal defined class Animal scala> class Mammal extends Animal defined class Mammal scala> class Dog extends Mammal defined 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.test res2: Animal =

15 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 Animal class Person class Student extends Person def owner(f: Dog => Person) { println("ok") } def dogOwner(d: Dog) = new Person // exactly as expected def petOwner(d: Dog) = new Student // return is subtype def animalOwner(a: Animal) = new Person // arg is supertype The following calls are all legal, and all print ok: owner(dogOwner) owner(petOwner) owner(animalOwner)

16 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

17 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: Animal at Animals.main(Animals.java:9)

18 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 contravariant

19 Again, with pictures Suppose you have a function of type B → C
And suppose you would like to give the function a value of type A, and get back a value of type D D A A → → D B → C You can do this if A is a subtype of B, and C is a subtype of D

20 Again, with pictures Suppose you have a function of type 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 B → C You can do this if A is a subtype of B, and C is a subtype of D

21 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

22 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

23 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 as def :: (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]

24 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

25 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

26 The End


Download ppt "The Scala API."

Similar presentations


Ads by Google