val and var

val: you could not reassign the variant, but whether the variant is mutable or not depends on its own type.
the parameters are vals( functional programming)

Classes and Objects

singleton objects

  1. a class and its companion object can access each other’s private members.
  2. singleton objects inheriting from classes and traits in Chp 13
  3. you should inherit from Application only when your program is relatively simple and single-threaded.

Operators

operatros are methods

  1. infix: a + b : (a).+(b)
  2. prefix: +, -, ! and ~.(short hand of unary_+…)
  3. postfix: methods that take no arguments
  4. operator associativity: : right ro left.
    no matter what associativity an operator has, its operands are always evaluated left to right

Class

  1. the Scala compiler will place the code for the initializers of the fields into the primary constructor in the order in which they appear in the source code.
  2. abstact classes
    a class with abstract memeber must iself be declared abstract.
  3. using parameterless methods(when no parameter), it supports the uniform access principle, which says that client code should not be affected by a decision to implement an attribute as a field or method.
    encouraged: define methods that take no parameters and have no side effects as parameterless methods.

Inheritance

  1. subtyping means that a value of the subclass can be used wherever a value of the superclass is required.
  2. scala has two namespaces:

    1.  values(fields, methods, package, and singleton objects)
    
    1. types(class and trait names)

      so you could overriding a parameterless method with a field.

  3. factory object
    a factory object contains methods that construct other objects. Clients would then use these factory methods for object construction rather than constructing the objects directly with new

  4. Null is a subclass of every reference class. Nothing is a subtype of every other type.
  5. value equality: ==, reference equality: eq.
  6. How to write an equality method ?

    1.  override `equals` in class `Any`: `override def equals(other: Any) = ...`
    
    1. override hashCode method
    2. when equals and hashCode are defined in terms of mutable fields, you may need more things to do.
    3. to deal with the equality relationships between class and its subclass, you need to add one more method def canEqual(other: Any): Boolean for non-final class. For the example bellow, if the subclass ColoredPoint overrides canEqual, then the instance of ColoredPoint and Point is not equal, otherwise, it can be equal to a Point instance.

      //one example
      

      class Point(val x: Int, val y: Int) {
      override def hashCode = 41*(41 + x) + y
      override def equals(other: Any) = other match {

      case that: Point =>                (that canEqual this) &&
          (this.x == that.x) && (this.y == that.y)
      case _ => false
      

      }
      def canEqual(other: Any) = other.isInstanceOf[Point]
      }
      `

Build-in control structures

  1. Try to challenge while loops in your code in the same way you challenges vars. If there isn’t a good justification for a particular while or do-while loop, try to find a way to do the same thing without it.
  2. For expression
    using for expression may make things clearer
    `persons withFilter (p => !p.isMale) flatMap (p =>
    (p.children map (c => (p.name, c.name) ) )
    
    //clear
    for (p <- persons; if !p.isMale; c <- p.children)
    yield (p.name, c.name)
    
    </pre> in fact, everyforexpression can be expressed in terms of the three higher-order functionsmap,flatMapandwithFilter. So if you definemap,flatMap,withFilterandforeachmethods for your data type, your data types could supportforexpression. If you just define a subset of these methods, then your data type would support a subset of all possiblefor` expressions.
  3. live without break and continue, tail-call.

    1.  If the solution is tail recursive, there won’t be any runtime overhead to be paid.(_tail-call optimization_)
    
    1. tail-call optimization is limited to situations in which a method or nested function calls itself directly as its last operation.

Function and Closures

  1. programs should be decomposed into many small functions that each do a well-defined task.
  2. first-class functions
    Every function value is an instance of some class that extends one of several FuntionN traits in packages scala. Each FunctionN trait has an apply method used to invoke the function.
  3. partially applied functions
    someNumbers.forach(sum _)

    you could leave off the - here (only when a function type is expected).
  4. closures
    when a closure accesses some variable that has several different copies as the program runs, the instance used is the one that was active at the time the closure was created.

Control Abstraction

Curring

By-name parameters

<pre>`def byNameAssert(predicate: =&gt; Boolean) = 
    if (assertionsEnabled &amp;&amp; !predicate)
        throw new AssertionError

def boolAssert(predicate: Boolean) = 
    if(assertionEnabled &amp;&amp; !predicate)
        throw new AsserstionError

//evaluate (5&gt;3) before the call to boolAssert
boolAssert(5 &gt; 3)
//the expression (5&gt;3) is not evaluated before the call to byNameAssert.
byNameAssert(5 &gt; 3)
`</pre>

Traits

  1. A trait differs with a class:

    1.  no parameters
    
    1. super calls are dynamically bound
  2. if a trait delcares a superclass, then it can only be mixed into a class that also extends that superclass.
    `trait Doubling extends IntQueue {
    abstract override def put(x: Int) { super.put(2*x) }
    
    }
    </pre>supercall is dynamically bound, it will work so long as the trait is mixed in _after_ another trait or class that gives a concrete definition to the method.abstract override` (only used for traits) means that the trait must be mixed into some class that has a concrete definition ot the method.
  3. traits as stackable modifications
    val queue = (new BasicIntQueue                    with Filtering with Incrementing)

    traits further to the right take effect first. when determine the super call, use linearization!4. If it might be reused in multiple, unrelated classes, use trait;
    if you want to inherit from it in Java code, use abstract class;
    if you plan to distribute it in compiled form, lean towards an abstract class;
    if efficiency is very important, lean towards using a class.

Imports

  1. flexible:

    *   may appear anywhere
    
    • may refer to objects(singleton or regular) in addition to packages
    • let you rename and hide some of the imported members
      `import Fruits.{Apple => McIntosh}   //rename apple
      //import all Fruits except for Apple
      import Fruits.{Apple => _, _}
      `
  2. scope of protection
    private[X] or protected[X] means that access is private or protected “up to” X, where X disignates some enclosing package, class or singleton object.
  3. package objects
    Each package is allowed to have one package object.

Assertions and Unit Testing

to be read

Case Classese && Pattern Matching && Extractors

  1. case classes

    1.  _case class_ addes a factory method with the name of class.2.  all arguments in the parameter list of a case class implicitly get a     `val` prefix, so they are maintained as fields.
    
    1. the compiler addes methods toString, hashCode, equals to case class.
    2. the compiler adds a copy method for making modified copies.
  2. a variable pattern matches any object, Scala binds the variable to whatever the object is.
    To treat a lowercase identifier as a constant in a pattern match, use back-tick pi.
  3. typed patterns
    `def generalSize(x: Any) = x match {
        case s: String => s.length
        case m: Map[_, _] => m.size
        case _ => -1
    }
    `
    because of _type erasure_, you could not chek `case m: Map[Int, Int]`. Only exception to the erasure rule is arrays. `case a: Array[String]` . The element type of an array is stored with the array value, so you can pattern match on it. variable binding:
    `expr match {
        case Unop("abs", e @ Unop("abs", _) ) => e
        case _ =>    }
    `
  4. A sealed class cannot have any new subclasses added except the ones in the same file. If we want Scala compiler help to detect missing patterns, we should make the superclass of case classes sealed.
  5. case sequences as partial functions6. patterns in for expressions
    for (Some(fruit) &lt;- results) println(fruit)
    Extractors


  6. A extractor is an object that has a method called unapply or unapplySeq.

    `object Domain {
        def apply(parts: String*): String =            parts.reverse.mkString(".")
        def unapplySeq(whole: String): Option[Seq[String]] =            Some(whole.split("\\.").reverse)
    }
    dom match {
        case Domain("org", "acm") => println("acm.org")
        case Domain("net", _*) => println("a .net domain")
    `
  7. Compared with case classes, extractors is representation independence, that’s to say, patterns have nothing to do with the data type of the object that’s selected on. While case classes also have their advantages: short code and more efficient.

Collections

List & Sets and Maps

  1. type inference algorithm:
    Type inference is flow based. In a method application m(args), it first checks whether the method m has a known type. If it has, that type is used to infer the expected type of the arguments.
    msort((x: Char, y: Char) =&gt; x &gt; y)(abcdb)
    abcde sortWith (_ &gt; _)

    the type of abcde is List[Char], so we do not need to write it explicitly, could just use _.
  2. When designing a polymorphic method that takes some non-function arguments and a funtion argument, place the function argument last in a curried parameter list.( The methods’ correct instance type can be inferred from the non-function arguments).
  3. scala.collection.mutable.Set() and scala.collection.mutable.Map() usually uses hash talbe. While for scala.collection.immutable.{Set(), Map()}, it depends how many elements you pass to it. If there are more than 5 elements, then they use hash methods.

collection hierarchy

  1. the difference between Traversable and Iterable ?
    see discussion in stackOverflow
  2. All collections except streams and views are strict. The only way to go from a strict to a lazy collection is via the view method. The only way to go back is via force.
  3. a view is a special kind of collection that represents some base collection, but implements all of its transformers lazily.

    1.  Using view could avoiding intermediate results.
    
    1. create a subwindow for mutable sequences to update selectively some elements of that sequence.
      `findRalindrome(words.view take 10000) //1
      //2
      val arr = (0 to 9).toArray
      val subarr = arr.view.slice(3, 6)
      do_something(subarr) // update partial of arr
      `
  4. Factoring out common operations
    CanBuildFrom: check this post
  5. integrate a new collection class into the framework
    1.  decide whether the collection should be mutable or immutable
    
    1. pick the right base traits for the collection
    2. inherit from the right implementation trait to implement most collection operations
    3. if you want map and similar operations to return instances of your collection type, provide an implicit CanBuildFrom in your class’s companion object.

Type Parameterization

variance annotations

  1. covariant(+), contravariant(-), nonvariant
  2. In a purely functional word, many types are natureally covariant. However, the situation changes once you introduce mutable data. In fact, if a generic parameter type appears as the type of a method parameter, the containing class or trait may not be covariant in that type parameter.
  3. In scala, arrays are nonvariant. you could cast an array of Ts to an array of any supertype of T
    `val a1 = Array("abc")
    val a2: Array[Object] =        a1.asInstanceOf[Array[Object]]
    `
  4. lower bound
    `class Queue[T](private val leading: List[T],
    private val trailing: List[T] ) {
    def enqueue[U &gt;: T](x: U) =            new Queue[U](leading, x :: trailing)//...
    
    }
    </pre> You coud append anOrangeto aQueue[Apple]. The result will be aQueue[Fruit]`.s
  5. Liskov Substitution Principle: It is safe to assume that a type T is a subtype of a type U if you can substitute a value of type T whereer a value of type U is required. The principle holds if T supports the same operations as U and ll of T‘s operations require less and provides more than the corresponding operations in U.
    When you write the function type A =&gt; B, Scala expands this to Function1[A,B].
    `trait Function[-S, +T] {
    def apply(x: S): T
    
    }
    </pre> TheFunction1in the trait is contravariant in the function argument typeSand covariant in the result typeT`, because argument are somthing that’s required, whereas results are something that’s provided.
  6. upper bound
    def orderedMergeSort[T &lt;: Ordered[T]](xs: List[T]): List[T] = {
    ...
    }

    Means the element type of the list passed to orderedMergeSort must be a subtype of Ordered.
  7. object private data
    `class Queue[+T] private(
    private[this] var leading: List[T],
    private[this] var trailing: List[T]
    
    ){ … }
    </pre> Here typeTis a covariant type, butleadingandtrailingare variable, there should be a contravariant position, there will be a compiler error. But if we markprivate[this]`, the compiler has special handling in it’s variance checking for this case.

Abstract Members

  1. one example
    `trait Abstract {
        type T  //abstract type
        def transform(x: T): T
        val initial: T
        var current: T
    }
    `
  2. For abstract vals, it could only be implemented by a val definition; For abstract method, it may be implemented by both concrete method definitions and concrete val definitions.
  3. initializing abstract vals

    `trait RationalTrait {

    val numerArg: Int
    val denomArg: Int
    

    }
    //anonymous class
    new RationalTrait {

    val numerArg = 1
    val denomArg = 2
    require(denomArg != 0)//exception
    ...
    

    }
    //pre-initialized
    new {

    val numerArg = 1 * x
    val denomArg = 2 * x
    

    } with RationalTrait
    </pre> Here we first define a traitRationalTraitwith abstract vals, then we have an _anonymous class_ that mixes in the trait. The anonymous class is initialized _after_ theRationalTrait, so the values ofnumerArganddenomArgare not available during the initialization ofRationalTrait(i.e. theses two are 0). so therequireinvocation will fail. so, a class parameter argument is evaluated _before_ it is passed to the class constructor(unless by-name). An implementingval` definition in a subclass, by contrast, is evaluated only after the superclass has been initialized. Two solutions:

    *   pre-initialized
    
    • lazy vals
  4. path-dependent types
    `class DogFood extends Food
    class Dog extends Animal {
    type SuitableFood =  DogFood
    override def eat(food: DogFood) {}
    
    }
    val bessy = new Dog
    val lassie = new Dog
    </pre>bessy.SuitableFoodis a _path-dependent type_ and it’s the same type aslassie.SuitableFood. while <pre>class Outer {
    class Inner
    
    }
    val o1 = new Outer
    val o2 = new Outer
    </pre>o1.Inneris a different type aso2.Inner. They are subtypes ofOuterInner`.
  5. structural subtyping
    you get a subtyping relationship simply because two types have the same members.
    *   If you want to define a _Pasture_ class that contains animals that eat grass, you could write the type `Animal { type SuitableFood = Grass }`. so you could define _Pasture_ like this:
    
    class Pasture {
    val animals: List[ Animal {type SuitableFood = Grass} ] = Nil
    }
    • If you want to group together a number of classes that were written by someone else.
      def using[T &lt;: { def close(): Unit }, S](obj: T)
      (operation: T =&gt; S) = {
      val result = operation(obj)
      obj.close()
      result
      }

      No base type is specified, so Scala would use AnyRef automatically, and the type T must support close() method.

Implicit Conversions and Parameters

  1. rules for implicits:

    1.  Marking Rule: Only definitions marked `implicit` are available.
    
    1. Scope Rule: An inserted implicit conversion must be in scope as a single identifier, or be associated with the source or target type of the conversion(i.e. companion object).
    2. One-at-a-time Rule: Only one implicit is tried.
    3. Explicits-First Rule: Whenever code type checks as it is written, no implicits are attempted.
  2. Where implicits are tried:

    1.  implicit conversion to an expected type
    

    `//1
    implicit def int2double(x: Int): Double = x.toDouble
    var i: Double = 1
    //2 receiver
    implicit def intToRational(x: Int) = new Rational(x, 1)
    1 + oneHalf //intToRational(1) + oneHalf
    //3 def maxListT

    (implicit orderer: T =&gt; Ordered[T]): T =        elements match{
        case List() =&gt;
            throw new IllegalArgumentException(&quot;empty list!&quot;)
        case List(x) =&gt; x
        case x :: rest =&gt;
            val maxRest = maxList(rest) //(orderer) is implicit
            if (x &gt; maxRest) x //orderer(x) is implicit
            else maxRest
    }
    

    maxList(List(1,5,10,3)) //res: Int = 10
    //view bound
    def maxList2T <% Ordered[T] : T = { …. }
    //upper bound
    def maxList3[T <: Ordered[T] }(elements: List[T]): T = { … }

    2.  Converting the receiver: interoperating with new types; simulating new syntax
    
    3.  implicit parameters
    

    view bound: We could use view bound to shorten the method header.
    The difference between view bound and upper bounds T &lt;: Ordered[T] is that upper bounds require that T is a subtype of Ordered[T], however, for view bound, it only requires that T can be treated as an Ordered[T]. So we could pass a List[Int] to maxList and maxList2 but no to maxList3.

  3. multiple conversions
    choose a more sprcific one. One implicit conversion is more spercific than another if one of the following applies:

    1.  The argument type of the former is a subtype of the latters’s
    
    1. Both conversions are methods, and the enclosing class of the former extends the enclosing class of the latter.

Annotations

  1. standard annotations:
    @deprecated @volatitle @serializable @SerialVersionUID @transient
    `@scala.reflect.BeanProperty@tailrec@unchecked@native`

Modular Programming Using Object

  1. self type
    check this post in StackOverflow.
  2. singleton type
    A singleton type is extremely specific and holds only one object. check this post

Actors and Concurrency

not too much to record, the example showed in Programming in Scala is worth understanding.