Study note of the chapter 23, 26, 27 of the book: Programming In Scala, 4th Edition.

Chapter 23 For Expression Revisisted

For expression syntax is for (seq) yield expr where seq is a sequence of generator, defintions and filters. A generator is is of the form pat <- expr, if the pattern matches, the variables in the pattern get bound to the element parts. If the match failes, the element is discarded from the iteration.

The translation of for expressions is as the following:

  • for (x <- expr1) yield expr2: => expr2)
  • for (x <- expr1 if expr2) yield expr3: expr1.withFilter(x => expr2) yield expr3
  • for (x <- expr1 if expr2; seq) yield expr3: for(expr1.withFilter(x => expr2; seq) yield expr3
  • for (x <- expr1; y<-expr2; seq) yield expr3: expr1.flatMap(x => for (y <- expr2; seq>) yield expr3)
  • for (x <- expr1; y = expr2; seq) yield expr3: for((x, y) <- for (x <- expr1) yield (x, expr2); seq) yield expr3
  • for(x <- expr1) body: expr1 foreach (x => body)
  • for(x <- expr1, if expr2) body: expr1 withFilter(x => expr2) foreach (x => body)

Rules for generalizing for

  • If just define map, it allows single generator.
  • If define map and flatMap, it allows multiple generator.
  • If define foreach, it allows for loop.
  • If define withFilter, it allows if in the for expression.

Chapter 26 Extractors

An extractor is an object that defines an unapply method that matches a value and take it apart. The apply method of an object is called an injection because it takes some arguments and creates an elemnt of a give type. The unapply method is called an extraction because it takes an elmeent into parts. They are dual to each other.

The unaplly method may return a Some of a tuple that has two or more elements, or Some(x) for one variable, or Boolean for empty variable. Use Some(Seq[T]) for vararg matching (_* in pattern).

Unlike case classes that bind a type to a pattern, the extractor enables representation independence.

Use Regex or .r postfix to define a regular expression. Each expression is also an extractor that is used to identify substrings that are matched by the groups of the regular expression.

Chapter 27 Annontation

Annotations are structured information added to program source code. They are used by meta-programming tools. Scala compiles understands annotations but leaves them to individual tools to process them. Commonly used annotations:

  • @deprecated
  • @unchecked
  • @volatile
  • @SerialVersionUID used with Serializable trait
  • @transient for not-serializable fields
  • @tailrec for tail-recursive methods.
  • @native: JNI interface

Chapter 29 Modular Programming Using Objects

Use objects for modules. Use classes for module templates (interfaces). Use traits to split modules into separate files.

Use self type to specify that a trait is to be mixed with another type.

Because nested classes are path dependent, use singleton type syntax a.type to help compiler.

Chpater 32 Futures and Concurrency

Future is Scala’s solution for concurrency: it allows a series of asynchronous transformations of immutable state represetned by Future. It avoids shared memory and locks. For backcompatibility, Scala support wait, notify, notfiyAll and synchronized.

32.1 Execution Context and Trys

Future represents a computation to be performed asynchronously. Many operations on Future also executed in a different thread. Both Future and many of its operations require an implicit ExecutionContext. Scala provides one

The result has a type of Some[Try[T]]. When isCompleted is false, the result is None. Otherwise, the value method returns an Success[T] for a success and Failure[T] for a failure.

32.2 Operarions

  • Run an async operation
    • Future(expr): the apply method.
  • Transformation
    • map: returns a new future that asynchronously transforms the orginal asynchronously computed result.
    • for expression: for serializes its transformation. Futures created inside for expression are execuited sequentially.
    • flatten: falts a [Future[Future[T]]] value into a [Future[T]] value.
  • Creation: create already completed futures, doesn’t need ExecutionContext
    • Future.successful: a Success[T]
    • Future.failed: a Failure[Throwable]
    • Future.fromTry: a Success[T] or a Failure[Throwable] based on the argument
    • Promise: first create a Promise[T], then call its success(value) or failure(exception) method, complete(tryValule), or completeWith(aFuture). Use future to get the created future object.
  • Filtering a Future object
    • filter: if future is failed, the filter is ignore. If future is succeeded, if the filter is satisfied, return the success value, otherwise, return an exeption.
    • withFilter: used in for expression
    • collect partialFunction: filter and transofrm.
  • Dealing with failure
    • failed: returns a new future that flips the failure and success
    • fallbackTo: an alternate future to use in case of the orginal future fails.
    • recover partialFunction: recover with a value when there is a match for failed result
    • recoverWith partialFunctoin: recover with a new future when there is a match for failed result
    • transform(res => ???, ex => ???): handle both success and failure. The pattern can be a Try mapped toanther Try that allows you to control the success or failure.
    • transformWith(): transform a future using Try => Future function.
  • Combine Futures
    • zip: transform two successful futures into a future tuple of both values. If there is a failure, first failure returns.
    • zipWith: zip and transform
    • Future.foldLeft/Future.reduceLeft: accumulates a ressult across an Iterable collection of futures.
    • Future.sequnce: transforms a TraversableOnce collection of futures into a future TraversableOnce of values.
    • Future.traverse: transforms a TraversableOnce of any element type to a TraversableOnce of future of TraversableOnce of values.
  • Performing side-effects

    • foreach: perform a side effect on success, nothing on failure. Also support the for loop syntax
    • onComplete { case Success(res) => ???; case Failure(ex) => ???}
    • andThen { case Success(res) => ???; case Failure(ex) => ???}: can control the order of andThen callbacks.

32.3 Testing With Futures

Await.result watis for value synchornously.

ScalaFuture trait adds a futureValue to a future.

Scalatest introduces AsyncFunSpec.

The pattern is staying asynchronously by performing a series of transformations. To get results out of future space, register side effects to be performed asynchronously once futures complete.