This post contains a collection of examples of Scala classes and class properties. I created most of these in the process of writing the Scala Cookbook.
Unlike the Cookbook, I don’t describe them much here, I just show the examples, mostly as a reference for myself (and anyone else that can benefit from them).
Basic Scala class examples
# a basic class class Person(var name: String, var age: Int) # use the class val al = new Person("Al", 42) al.name // "Al" al.age // 42
A bit more real-world:
// define the class class Person(val firstName: String, val lastName: String) { println("the constructor begins") val fullName = firstName + " " + lastName val HOME = System.getProperty("user.home"); // define some methods def foo { println("foo") } def printFullName { // access the fullName field, which is created above println(fullName) } printFullName println("still in the constructor") } // demonstrate the class in the repl scala> val p = new Person("Alvin", "Alexander") the constructor begins Alvin Alexander still in the constructor p: Person = Person@68f507d2
The visibility of class parameters
A look at the visibility of class parameters:
// 'name' is a var class Person(var name: String) val p = new Person("Alvin Alexander") p.name // String = Alvin Alexander p.name = "Fred Flintstone" // String = Fred Flintstone // 'name' is a val class Person(val name: String) val p = new Person("Alvin Alexander") p.name // String = Alvin Alexander p.name = "Fred Flintstone" // error: reassignment to val // 'name' is neither var or val class Person(name: String) val p = new Person("Alvin Alexander") p.name // error: value name is not a member of Person // 'name' is 'private var' class Person(private var name: String) { def printName {println(name)} } val p = new Person("Alvin Alexander") p.name // error: variable name in class Person cannot be accessed in Person p.printName // Alvin Alexander
What var, val, and default mean when applied to class parameters:
Declaration Getter? Setter? ----------- ------- ------- var yes yes val yes no default no no
Auxiliary constructors
Define auxiliary constructors using this
as the name for each auxiliary constructor. Make sure you call a previously defined constructor:
class Pizza { var crustSize = 12 var crustType = "Thin" def this(crustSize: Int) { this() this.crustSize = crustSize } def this(crustSize: Int, crustType: String) { this(crustSize) this.crustType = crustType } override def toString = { "A %s inch pizza with %s crust.".format(crustSize, crustType) } }
That class defines three constructors, which can be called like this:
object AuxiliaryConstructors extends App { println(new Pizza) println(new Pizza(14)) println(new Pizza(16, "Thick")) }
Running this object results in the following output:
A 12 inch pizza with Thin crust. A 14 inch pizza with Thin crust. A 16 inch pizza with Thick crust.
Private constructor
A simple way to enforce the Singleton pattern in Scala is to make the primary constructor private, then put a getInstance
method in the companion object of the class:
class Brain private { override def toString = "This is the brain." } object Brain { val brain = new Brain def getInstance: Brain = { brain } } object SingletonTest extends App { // this won't work // val brain = new Brain // this works val brain = Brain.getInstance println(brain) }
Default values for constructor parameters
You can provide default values for constructor parameters:
class Socket (var timeout: Int = 10000) // create instance without a param, get the default value val s = new Socket s.timeout // Int = 10000 // specify your own timeout value val s = new Socket(5000) s.timeout // Int = 5000
When to use an abstract class
Why use an “abstract class”? It can have constructor parameters, but a trait cannot.
Traits don’t allow constructor parameters:
// this won't compile trait Animal(name: String) // so use an abstract class abstract class Animal(name: String)
In the following example the methods save
, update
, and delete
are defined in the abstract class BaseController
, and the method connect
is undefined, and therefore abstract:
abstract class BaseController(db: Database) { def save { db.save } def update { db.update } def delete { db.delete } def connect // abstract since it has no implementation def getStatus: String // an abstract method that returns a String def setServerName(serverName: String) // an abstract method that takes a parameter }
JavaBean classes
To create JavaBean classes, use the @BeanProperty
annotation on your fields, also making sure to declare the fields as the type var
. The @BeanProperty
annotation can be used in a constructor:
import scala.reflect.BeanProperty class Person(@BeanProperty var firstName: String, @BeanProperty var lastName: String, @BeanProperty var age: Int) { // more code here ... }
It can also be used on fields in a class:
import scala.reflect.BeanProperty class EmailAccount { @BeanProperty var accountName: String = null @BeanProperty var username: String = null @BeanProperty var password: String = null @BeanProperty var mailbox: String = null @BeanProperty var imapServerUrl: String = null @BeanProperty var minutesBetweenChecks: Int = 0 @BeanProperty var protocol: String = null @BeanProperty var usersOfInterest = new java.util.ArrayList[String]() }
Scala case classes
You can generate a lot of useful boilerplate code with a case class:
case class Person(var name: String, var age: Int)
With the special case class
incantation, Scala generates a great deal of code for you:
- toString, equals, and hashCode methods.
- The constructor parameters you specify become properties with getters and setters.
- You no longer have to use ’new’ to create an instance of your class.
- You can use convenient extractors in match/case statements.
To see the code that Scala generates for you, first compile a simple class, then disassemble it with javap
. First, put this code in a file named Person.scala:
case class Person(var name: String, var age: Int)
Then compile the file:
$ scalac Person.scala
This creates two class files, Person.class and Person$.class. Disassemble Person.class to see its signature:
$ javap Person Compiled from "Person.scala" public class Person extends java.lang.Object implements scala.ScalaObject,scala.Product,scala.Serializable{ public static final scala.Function1 tupled(); public static final scala.Function1 curry(); public static final scala.Function1 curried(); public scala.collection.Iterator productIterator(); public scala.collection.Iterator productElements(); public java.lang.String name(); public void name_$eq(java.lang.String); public int age(); public void age_$eq(int); public Person copy(java.lang.String, int); public int copy$default$2(); public java.lang.String copy$default$1(); public int hashCode(); public java.lang.String toString(); public boolean equals(java.lang.Object); public java.lang.String productPrefix(); public int productArity(); public java.lang.Object productElement(int); public boolean canEqual(java.lang.Object); public Person(java.lang.String, int); }
Also disassemble Person$.class to see its signature:
$ javap Person$ Compiled from "Person.scala" public final class Person$ extends scala.runtime.AbstractFunction2 implements scala.ScalaObject,scala.Serializable{ public static final Person$ MODULE$; public static {}; public final java.lang.String toString(); public scala.Option unapply(Person); public Person apply(java.lang.String, int); public java.lang.Object readResolve(); public java.lang.Object apply(java.lang.Object, java.lang.Object); }
The protected keyword
The protected
keyword:
- the protected keyword in scala has a different meaning than in java
- protected means current class and subclasses can access member
- unlike java, other classes in package can’t access member
Example:
package foo { class Foo { // (1) make 'getFoo' protected. protected def getFoo = "foo" } class FooSub extends Foo { def doFoo = { // (2) we can access getFoo because we're a subclass of Foo val x = getFoo } } class Bar { def doBar = { val f = new Foo // (3) this line won't compile because getFoo is protected //f.getFoo } } } package baz { import foo.Foo class Baz { def doBaz = { val f = new Foo // (4) this won't work either //f.getFoo } } }
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
Summary
In summary, I hope these Scala class examples have been helpful. I’ll keep adding more to these examples as time goes on.