Classes and Objects and Traits And Other Miscellany
Classes and Objects and Traits And Other Miscellany 24 -Nov-20
Classes, objects, case classes, traits n A Scala class is like a Java class n n A Scala object is like a Java “singleton” class n n All constructor parameters are implicitly val (fields) Free implementations of equals, hash. Code, to. String, copy, and a factory method Case classes support pattern matching A Scala trait is like a Java interface n n If you want exactly one of a given kind of object, just define it directly; no need to create a class first A Scala case class is just a class with extra goodies n n Use the class to create “objects” or “instances” of the class Scala traits may include “concrete” methods, not just abstract ones Scala has no special “inner classes” as in Java n In Scala you can nest almost anything in anything else
Classes n n Syntax: class Class. Name(parameters) { body } The class definition is the (primary) constructor n n Parameters and body are optional Parameters, if any, are marked with: n var n n val n n A val parameter will create a field and a getter, but no setter Neither val nor var n n A var parameter will cause a field, getter, and setter to be included: var p: Int gives the methods p: () => Int and p_=: Int => () Can be used within the body of the class, but not create a field or any methods Generated methods may be overridden in the class
Constructors n The class definition is the primary constructor n n Auxiliary (additional) constructors have the syntax n n When creating a new object, the code within the class is executed def this(parameters) { call to a constructor declared earlier (this is required) rest of code } Calling a constructor is just as in Java n new Person("Dave")
Examples I n n n n scala> class Person(val first. Name: String, var last. Name: String, age: Int) defined class Person scala> val mary = new Person("Mary", "Smith", 23) mary: Person = Person@d 73 c 3 c scala> mary. first. Name res 22: String = Mary scala> mary. last. Name res 23: String = Smith scala> mary. first. Name = "Sally" <console>: 7: error: reassignment to val scala> mary. last. Name = "Jones" res 24: String = Jones scala> mary. age <console>: 8: error: value age is not a member of Person scala> mary. last. Name res 25: String = Jones 5
Examples II n Again, but this time with a method: n n n scala> class Person(val first. Name: String, var last. Name: String, age: Int) { | override def to. String = first. Name + " " + last. Name + ", age " + age |} defined class Person scala> val mary = new Person("Mary", "Smith", 23) mary: Person = Mary Smith, age 23 scala> println(mary) Mary Smith, age 23 6
Object n n n An object is defined similar to the way that a class is defined, but it cannot take parameters Syntax: object Object. Name { body } A program’s main method is defined in an object: n n def main(args: Array[String]) { body } This is exactly analogous to Java’s main method n public static void main(String[] args) { body }
Companion objects n n Scala’s equivalent of static is the companion object The companion object of a class n n has the same name as the class is defined in the same file as the class The object and class can access each other’s private fields and methods In the class, access to the fields and methods in the companion object must be qualified with the name of the object
Abstract classes n n n To define a method as abstract, simply omit its body To define a field as abstract, omit its initial value A class containing abstract methods or fields must be declared abstract As in Java, an abstract class is one that cannot be instantiated In a concrete subclass, you do not need the override keyword
Case classes n Syntax: case class Class. Name(parameters) { body } n All the parameters are implicitly val n n n A parameter can be explicitly declared as var (not recommended) to. String, equals, hash. Code, and copy are generated (unless you supply them) apply and unapply are also generated n n apply lets you omit the word new when you create objects unapply lets you use the objects in pattern matching
Case classes can be pattern matched n scala> case class Person(age: Int, name: String) defined class Person scala> val dave = Person(40, "Dave") dave: Person = Person(40, Dave) scala> dave match { | case Person(a, n) if a > 30 => println(n + " is old!") | case _ => println("Whatever") |} Dave is old! scala> val quinn = Person(25, "Quinn") quinn: Person = Person(25, Quinn) scala> quinn match { | case Person(a, n) if a > 30 => println(n + " is old!") | case _ => println("Whatever") |} Whatever
Case classes in pattern matching n n sealed abstract class Move case object Left extends Move case object Right extends Move case object Up extends Move case object Down extends Move direction match { case Left => x -= 1 case Right => x += 1 case Up => y -= 1 case Down => y += 1 }
Traits n n n Traits are like Java’s interfaces Syntax: trait Trait. Name { body } Unlike Java, traits may have concrete (defined) methods A class extends exactly one other class, but may with any number of traits Syntax: n n class Class. Name(parameters) extends Other. Class with Trait 1, …, Trait. N { body } class Class. Name(parameters) extends Trait 1 with Trait 2, …, Trait. N { body }
Pattern matching with match n You have seen pattern matching with match and literals n n today match { case "Saturday" => println("Party!") case "Sunday" => println("Pray. . ") case day => println(day + " is a workday. : ( ") } You can match with types n something match { case x: Int => println("I'm the integer " + x) case x: String => println("I'm the String "" + x + """) println("My length is " + x. length) case _ => println("I don't know what I am! : ( ") }
Pattern matching in assignments n You can pattern match on tuples: n n But… n n scala> val (a, b, c) = (3, 5, 7) a: Int = 3 b: Int = 5 c: Int = 7 scala> val a, b, c = (3, 5, 7) a: (Int, Int) = (3, 5, 7) b: (Int, Int) = (3, 5, 7) c: (Int, Int) = (3, 5, 7) You can pattern match on lists: n n scala> val list = List("once", "upon", "a", "time") list: List[java. lang. String] = List(once, upon, a, time) scala> val first : : second : : rest = list first: java. lang. String = once second: java. lang. String = upon rest: List[java. lang. String] = List(a, time)
Operations and methods As operation As method call Unary prefix scala> -5 res 4: Int = -5 scala> 5 unary_res 5: Int = -5 Unary scala> " abc " trim res 6: java. lang. String = abc scala> " abc ". trim() res 7: java. lang. String = abc Binary scala> "abc" + "xyz" scala> "abc". +("xyz") res 8: java. lang. String = abcxyz res 9: java. lang. String = abcxyz scala> "abcdef" substring 2 res 10: java. lang. String = cdef >2 operands scala> "abcdef". substring(2) res 11: java. lang. String = cdef scala> "abcdef" substring (1, 3) scala> "abcdef". substring(1, 3) res 12: java. lang. String = bc res 13: java. lang. String = bc 16
Parameters in braces n A block consists of any number of statements inside braces, { } n n n When a method takes just one parameter, you can put that parameter inside braces instead of parentheses n n n The last value in the block is the value of the block Parentheses, ( ), can’t enclose multiple statements scala> "abcdefg" substring { 2 } res 0: java. lang. String = cdefg This example is pointless and looks silly Sometimes, you may want to compute that parameter by a series of statements n n scala> println { | var x = 2 | while (x < 1000) x *= 2 |x |} 1024 This isn’t a great example either, but it does make the point 17
Methods with no parameters n You can define a “parameterless” method: n n You can define an “empty paren” method: n n n scala> def hello = println("Hello!") hello: Unit scala> hello Hello! scala> hello() <console>: 7: error: hello of type Unit does not take parameters scala> def hi() = println("Hi!") hi: ()Unit scala> hi Hi! scala> hi() Hi! If you define a method without parentheses, you can’t call it with parentheses You can replace a parameterless method with an empty paren method, without affecting user code (but not vice versa) 18
Uniform access n In Java, the length of an array is a field, so you have to say my. Array. length; but the length of a String is a field, so you have to say my. String. length() n n However, if I say foo = bar, or println(bar), I am using bar like a variable, so I expect bar to act like a variable: n n n This violates the principle of uniform access: The user shouldn’t have to know whether it’s a field or a method bar should not do I/O bar should not change mutable state bar should not depend on values in mutable state In other words, if bar is a function, it should be a pure function Scala convention: When you call a method that does one of the above (impure) things, use parentheses 19
Types n Types can be “aliased” (named) n n type Word = String type Sentence = List[Word] type Paragraph = List[Sentence] This is a simple thing that can be extremely helpful when dealing with complex data types
The End
- Slides: 21