Short Introduction to Scala
Total Page:16
File Type:pdf, Size:1020Kb
INTRODUCTION Object/functional programming language Based on Java Virtual Machine Full interoperability with Java libraries Pure object orientation (no primitive types) Every function is a value High order functions (lambdas) SHORT INTRODUCTION TO SCALA Promoting immutability Currying INGEGNERIA DEL SOFTWARE Pattern matching Università degli Studi di Padova 2014: version Statically typed 2007: 2.11 (JVM 8) Dipartimento di Matematica 2006: the «growth Intelligent type system 2004: version Corso di Laurea in Informatica, A.A. 2014 – 2015 2.0 year» 2003: version Extensible internal 1.0 use to [email protected] EPFL Ingegneria del software mod. B Riccardo Cardin 2 INTRODUCTION INTRODUCTION Language main features Language main features Read‐Eval‐Print‐Loop (REPL) interpreter Every statement is a "pure" expression An interactive shell to execute statements "on the fly" No return statement needed! Variables The if-else statement is a value UML syntax ‐> name : type val y = 4 val x: Int = 1 + 1 Immutable // x has type String lazy val x: Int = 1 + 1 Immutable and lazy val x = if (y < 3) "minor" else "greater" var x: Int = 1 + 1 Mutable Imperative for statement is not supported def x: Int = 1 + 1 Executed every time Use the for-yield statement instead Very smart type inferer val x = 1 x: Int // Returns an array of integers between 2 and 101 for (i <- (1 to 100)) yield i + 1 No semicolon Blocks, blocks everywhere... Every char can be used to define names (%$#@?...) Ingegneria del software mod. B Riccardo Cardin 3 Ingegneria del software mod. B Riccardo Cardin 4 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Everything is an object Classes Values class Person(val name: String, val surname: String, val birth: Date) { // Main Ctor body here // Every secondary Ctor must call the main Ctor as // first statement (very restrictive) def this(name: String) = this(name, "", null) def age(): Int = { /* return the age */ } // Override intention must be declared override def toString = s"My name is $name $surname" References (Scala and Java) } Ingegneria del software mod. B Riccardo Cardin 5 Ingegneria del software mod. B Riccardo Cardin 6 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Classes Main constructor is declared within Class name Ctor body is made of statements in class body Accessor methods are build automatically val immutable value, getter only var mutable value, getter and setter def defines methods (and functions too...) Use equal "=" iff the method is a function No public class You can have more than a class into a .scala file No static methods (wait a minute...) ...so let’s introduce objects notation! Ingegneria del software mod. B Riccardo Cardin 7 Ingegneria del software mod. B Riccardo Cardin 8 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Object Object Native Singleton pattern implementation Companion objects implement also Factory Method object ChuckNorris extends Person("Chuck Norris") { pattern natively There can be // This is a static method more than def roundhouseKick = "Roundhouse" Every apply method creates an instance of the class one apply!!!! } println ChuckNorris.roundhouseKick Syntactic sugar: Class.apply(...) Class(...) It’s like a class application (...function anyone?) There can be only one instance of ChuckNorris Companion object class Person(val name: String, An object called as an existing class val surname: String) Companion object’s methods are static method of the class object Person { // Factory method class Person(val name: String, val surname: String) def apply(n: String, s: String) = object Person { // Companion object new Person(n, s) def someStupidStaticMethod = "This is a static method" } } // Application of the class will return a new instance println Person.someStupidStaticMethod val ricky = Person("Riccardo", "Cardin") // No new operator Ingegneria del software mod. B Riccardo Cardin 9 Ingegneria del software mod. B Riccardo Cardin 10 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Object Abstract classes Used also to define the entry point of an application Also defines a main constructor The Java way It has to be called from the derived classes’ main Ctor object Hello { // Every object containing a main method could be abstract class Animal(val species: String) { // Executed. There are no restriction on file name def walk // Abstract method def main(args: Array[String]) { } println("Hello World!") class Person(val name: String, } val surname: String) } // Calling main ctor directly in class // definition The Scala way extends Animal("Human") { def walk = { /* Do some stuff */ } object Hello extends App { } // All the code in the object’s ctor body will be val ricky = new Person("Riccardo", "Cardin") // executed as our application. // Arguments are accessible via an ‘args’ variable, // available in the App trait println("Hello World!") } Ingegneria del software mod. B Riccardo Cardin 11 Ingegneria del software mod. B Riccardo Cardin 12 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Traits: interfaces or abstract classes? Traits Like interfaces, they have not a constructor Like an interface // No implementation at all To implement a single trait, use extends trait Sorter { Otherwise, use with (mixin) def sort(list: List[Int]): List[Int] } But, they can have methods with implementation class QuickSorter extends Sorter { def sort(list: List[Int]) = { /* Do something */ } and attributes } Similar (but more powerful) to default methods in Java 8 Like an abstract class Multiple inheritance problem trait AbstractDao { // No Ctor (wtf!) var pool: Array[Datasource] trait A { override def toString = "I’m A" } def getPool = pool // Implemented method trait B { override def toString = "I’m B" } def save // abstract method trait C { override def toString = "I’m C" } def delete // abstract method class D extends A with B, C } new D().toString // Prints ‘I’m C’ class UserDao extends AbstractDao { // Has to implement save and delete Class linearization: use the rightmost type (more or less...) } Ingegneria del software mod. B Riccardo Cardin 13 Ingegneria del software mod. B Riccardo Cardin 14 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Traits Traits and Objects Inside a mixin the super refers to the previuos trait Using the companion object of a trait, we can in the linearized‐type implement the Abstract Factory pattern Used to implement the Decorator pattern natively // Abstract factory trait AbstractFactory trait Employee { // Private classes’ scope is limited to the // ... // definition file def whois(): String private class ConcreteFactory1 extends AbstractFactory { /* ... */ } } private class ConcreteFactory2 extends AbstractFactory { /* ... */ } class Engineer(name: String, office: String) extends Employee object AbstractFactory{ trait ProjectManager extends Employee { def apply(kind: String) = abstract override def whois() { kind match { // super refers to the previuos trait on the left case “factory1" => new ConcreteFactory1 () super.whois(buffer) Statically binded case “factory2" => new ConcreteFactory1 () factory 2 println("and I’am a project manager too!") } } Decorator pattern } } val factory = AbstractFactory("factory1") new Engineer("Riccardo","Development") with ProjectManager Ingegneria del software mod. B Riccardo Cardin 15 Ingegneria del software mod. B Riccardo Cardin 16 OBJECT ORIENTED SCALA OBJECT ORIENTED SCALA Case classes and pattern matching Case classes and pattern matching Scala has a built in pattern matching mechanism Native implementation of Value Object pattern def matchTest(x: Int): String = x match { Case clauses are Obviously, case classes can be used in pattern case 1 => "one" evaulated from case _ => "many" top to bottom matching... } println(matchTest(3)) // Prints ‘many’ The match is done recursively on the structure of the type trait Term Case class: regular class that can be pattern‐matched case class Var(name: String) extends Term case class Fun(arg: String, body: Term) extends Term Turns all ctor params into val (immutable) constants def printTerm(term: Term) { term match { // The clauses uses placeholders for variables. Generates a companion object w/ apply methods // If we don’t need the value, we can use Var(_) Generates toString, equals and hashCode methods case Var(n) => properly print(“We have a variable!”) trait Term case Fun(x, b) => case class Var(name: String) extends Term print(“We have a function!”) Checks the equality case class Fun(arg: String, body: Term) extends Term } among attributes Var("x") == Var("x") // Prints true } Ingegneria del software mod. B Riccardo Cardin 17 Ingegneria del software mod. B Riccardo Cardin 18 MISCELLANEA MISCELLANEA Generics: more or less like Java Generics Option[A] type Subtyping of generic types is "invariant" A list with zero (None) or one element (Some[A]) class Node[T](elem: T) Native implementation of the Null Object Pattern val node = new Node(3) // Smart type inference No more NullPointerExceptions!! ...but it can also be used in a variant (+T) o trait Option[T] { contravariant (-T) fashion def isDefined: Boolean def get: T // Throws an exception if None There are also upper type bound (T<:A) and lower def getOrElse(t: T): T } type bound (T>:A) case class Some[T](elem: T) extends Option[T] case object None extends Option[Nothing] case class ListNode[+T](h: T, t: ListNode[T]) { def head: T = h Use them with pattern matching: results garanted! def tail: ListNode[T] = t def prepend[U >: T](elem: U): ListNode[U] = def negate(x: