ScalaSchool

Classes

Classes in Scala are very similar to classes in Java.

They are templates containing fields and methods. Like in Java, classes can be instantiated using the new construct, there can be many “instances” (or “objects”) of the same class.

In Scala there exists a special kind of class named case classes We’ll take about those later.

Classes in Scala cannot have static members. You can use Objects (see below) to achieve similar functionality as with static members in Java.

Class Definitions

    class MyClass(x: Int, val y: Int) {       // Defines a new type MyClass with a constructor
                                              // m.y is defined as a field.  x isn't accessible outside the class
      this() { this(1,1) }                    // Auxiliary constructor
      require(y > 0, "y must be positive")    // precondition, triggering an IllegalArgumentException if not met  
      def nb1 = x                             // public method computed every time it is called  
      def nb2 = y  
      private def test(a: Int): Int = { ... } // private method  
      val nb3 = x + y                         // computed only once  
      override def toString =                 // overridden method  
          member1 + ", " + member2 
    }

    new MyClass(1, 2) // creates a new object of type

Classes

Inheritance

class Employee(name: String) extends Person(name) {
  // Calls the primary constructor of superclass
  var salary = 0.0
  override def toString = super.toString + s"[salary=$salary]"
  // Use override when overriding a method
}

Java Type operations on Scala classes

// You *can* do Java like type operations (but usually Scala has better alternatives
if(p.isInstanceOf[Employee]) {  // Java isInstanceOf
  val e  = p.asInstanceOf[Employee]  // Like a Java cast
}

if(p.getClass == classOf[Employee]) ... // Like Java Employee.class

// Again you normally will use pattern matching instead of doing this type of  thing

Class methods

A method is a function that is a member of some class, trait, or singleton object. Scala has some interesting syntactic sugar to make calling methods more like natural language syntax.

scala> val b = new Object{ def set_=(a: Int) = println(a) }
b: java.lang.Object{def set_=(Int): Unit} = $anon$1@17e4cec

scala> b.set = 5
<console>:6: error: value set is not a member of java.lang.Object{def set_=(Int): Unit}
       b.set = 5
         ^

scala> val c = new Object{ def set = 0 ; def set_=(a:Int) = println(a) }
c: java.lang.Object{def set: Int; def set_=(Int): Unit} = $anon$1@95a253

scala> c.set = 5
5

Operator Notation

Infix Operators

You can write a identifier b where identifier denotes a method with two parameters (one implicit, one explicit). For example:

1 to 10

is actually a method call:

1.to(10)

This is called an infix expression because the operator is between the arguments.

Unary Operators

-a corresponds to a.unary_-. Likewise for +a,~a, and !a

Assignment Operators

a <operator>= b is equivalent to a = a <operator> b e.g.

class test(val x:Int) {
    def %%(y: Int) = new test(x*y)
}

var a = new test(10)
a.x // 10
a %%= 5 // Equivalent to a = a %% 5
a.x // 50
Notes on Assignment Operators:

Methods

Traits

Traits are like interfaces in Java, but they can also contain concrete members, i.e. method implementations or field definitions.

trait Logger {  // Traits can't have constructors
  def log(msg: String)  // abstract method
  def info(msg: String) = log(s"INFO $msg")  // traits can have concrete methods too
}

class App extends Logger with Auth { ... } // Mix in any number of traits

trait TimestampLogger extends Logger {  // Traits can extend Traits too
  abstract override def log(msg: String) = {  // Still abstract!
    super.log(s"${System.currentTimeMillis} $msg")
  }
}

trait ConsoleLogger extends Logger {
  override def log(msg: String): Unit = println(msg)
}

object App extends ConsoleLogger with TimestampLogger
   // App.log("Hi") calls log of LAST Trait mixed in; super.log calls the super of that trait

Traits and Abstract Classes

Objects

Object in Scala are like classes, but for every object definition there is only one single instance. It is not possible to create instances of objects using new, instead you can just access the members (methods or fields) of an object using its name.

Objects

Packages

Adding a statement such as package foo.bar at the top of a file makes the code in a file part of the package foo.bar. You can then do import foo.bar._ to make everything from package foo.bar available in your code. The content of a package can be scattered across many files. If you define a class MyClass in package foo.bar, you can import that specific class (and not anything else from that package) with import foo.bar.MyClass.

In Scala, everything can be imported, not only class names. So for instance if you have an object baz in package foo.bar, then import foo.bar.baz._ would import all the members of that object.

  import package_name.{A, B}    // imports A and B from the package called `package_name`
  import package_name._         // imports everything from the package called `package_name`
  import package_name.{A => B}  // imports A from the package called `package_name` and aliases it as B
                                //  This can be useful if you want to import 2 classes that have the same name.
  import package_name.{List => _, _}  // imports everything *except* List 

  // scala, scala.Predef, and java.lang are always imported

  def square(x): Double = {
    import scala.math._  // imports can be inside blocks
    pow(x,2)
  }
  
  import math._ // same as import scala.math._  Imports nest in Scala

Packages

Class hierarchies

    abstract class TopLevel {    // abstract class  
      def method1(x: Int): Int   // abstract method  
      def method2(x: Int): Int = { ... }  
    }

    class Level1 extends TopLevel {  
      def method1(x: Int): Int = { ... }  
      override def method2(x: Int): Int = { ...} // TopLevel's method2 needs to be explicitly overridden  
    }

    object MyObject extends TopLevel { ... } // defines a singleton object. No other instance can be created

Class Organization

Scala Class Hierarchy

Type Parameters

Conceptually similar to C++ templates or Java generics. These can apply to classes, traits or functions.

    class MyClass[T](arg1: T) { ... }  
    new MyClass[Int](1)  
    new MyClass(1)   // the type is being inferred, i.e. determined based on the value arguments  

It is possible to restrict the type being used, e.g.

    def myFct[T <: TopLevel](arg: T): T = { ... } // T must derive from TopLevel or be TopLevel
    def myFct[T >: Level1](arg: T): T = { ... }   // T must be a supertype of Level1
    def myFct[T >: Level1 <: Top Level](arg: T): T = { ... }