Classes and Cases

Download Report

Transcript Classes and Cases

Cases and Classes and Case Classes
And Other Miscellany
26-Jul-16
Classes and constructors, I

Every class has a constructor, which you write (no “invisible”
constructors, as in Java)



scala> class Person(val firstName:String, var lastName: String, age: Int)
defined class Person
The above is complete; no braces are needed unless you want to add code,
fields, or methods
The above defines:



firstName (immutable) with getter function firstName
lastName (mutable) with getter function lastName and setter function
lastName_=
 The method name uses an underscore, but you use it as an ordinary
assignment, for example, lastName = "Smith"
Nothing for age (it can be used as a val in the rest of the constructor)
2
Classes and constructors, II

Syntax: class ClassName(parameters) { body }


The ClassName should begin with a capital letter and be
CamelCase
This is the constructor, and it has parameters





A var parameter will cause a field, getter, and setter to be included:
var p: Int gives the methods p: () => Int and p_=: Int => ()
These methods can be redefined inside the method
A val parameter will create a field and a getter, but no setter
A parameter with neither val nor var does not create a field or any
methods, but it can be used within the body of the class
When a new object of this class is defined, the fields are
created, the methods are defined, and any “loose” code (not
within a def) is executed
Classes and constructors, III








scala> class Person(val firstName:String, var lastName: String, age: Int)
defined class Person
scala> val mary = new Person("Mary", "Smith", 23)
mary: Person = Person@d73c3c
scala> mary.firstName
res22: String = Mary
scala> mary.lastName
res23: String = Smith
scala> mary.firstName = "Sally"
<console>:7: error: reassignment to val
scala> mary.lastName = "Jones"
res24: String = Jones
scala> mary.age
<console>:8: error: value age is not a member of Person
scala> mary.lastName
res25: String = Jones
4
Classes and constructors, IV

Again, but this time with a method:



scala> class Person(val firstName:String, var lastName: String, age: Int) {
| override def toString = firstName + " " + lastName + ", 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
5
Auxiliary constructors


A class (as on the previous slide) defines its primary constructor
You can have additional, auxiliary constructors




The first statement within an auxiliary constructor must be a call to another
auxiliary constructor, or to the primary constructor
Thus, every object creation eventually ends up at the primary constructor
Syntax:
def this(parameters1) {
this(parameters2)
… more code…
}
Since these are overloaded constructors, parameters1 and
parameters2 must be different
Pattern matching with match

You have seen pattern matching with match and literals


today match {
case "Saturday" => println("Party! Party! Party!")
case "Sunday" => println("Pray....")
case day => println(day + " is a workday. :( ")
}
You can match with types

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

You can pattern match on tuples:


But…


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, Int) = (3,5,7)
b: (Int, Int, Int) = (3,5,7)
c: (Int, Int, Int) = (3,5,7)
You can pattern match on lists:


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)
Case classes

If you declare a class as a case class, you get some extra features:




It adds a factory method with the name of the class, so you can omit the word new
when you create a new object
All constructor parameters are implicitly val
You get reasonable implementations of toString, hashCode, and equals “for free”
Example:




scala> case class Person(firstName: String, lastName: String)
defined class Person
scala> val jane = new Person("Jane", "Eyre")
jane: Person = Person(Jane,Eyre)
scala> val Person(f, l) = jane
f: String = Jane
l: String = Eyre
scala> println(jane)
Person(Jane,Eyre)
Operations and methods
As operation
As method call
Unary prefix
scala> -5
res4: Int = -5
scala> 5 unary_res5: Int = -5
Unary
scala> " abc " trim
res6: java.lang.String = abc
scala> " abc ".trim()
res7: java.lang.String = abc
Binary
scala> "abc" + "xyz"
scala> "abc".+("xyz")
res8: java.lang.String = abcxyz res9: java.lang.String = abcxyz
scala> "abcdef" substring 2
res10: java.lang.String = cdef
>2 operands
scala> "abcdef".substring(2)
res11: java.lang.String = cdef
scala> "abcdef" substring (1, 3) scala> "abcdef".substring(1, 3)
res12: java.lang.String = bc
res13: java.lang.String = bc
10
Parameters in braces

A block consists of any number of statements inside braces, { }



When a method takes just one parameter, you can put that parameter inside
braces instead of parentheses



The last value in the block is the value of the block
Parentheses, ( ), can’t enclose multiple statements
scala> "abcdefg" substring { 2 }
res0: java.lang.String = cdefg
This example is pointless and looks silly
Sometimes, you may want to compute that parameter by a series of statements


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
11
Methods with no parameters

You can define a “parameterless” method:




You can define an “empty paren” method:





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)
12
Uniform access

In Java, the length of an array is a field, so you have to say
myArray.length; but the length of a String is a field, so you have
to say myString.length()


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:





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
13
The End