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
:expr1.map(x => 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
andflatMap
, it allows multiple generator. - If define
foreach
, it allowsfor
loop. - If define
withFilter
, it allowsif
in thefor
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 withSerializable
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 scala.concurrent.ExxecutionContext.Implicits.global
.
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)
: theapply
method.
- Transformation
map
: returns a new future that asynchronously transforms the orginal asynchronously computed result.for
expression:for
serializes its transformation. Futures created insidefor
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
: aSuccess[T]
Future.failed
: aFailure[Throwable]
Future.fromTry
: aSuccess[T]
or aFailure[Throwable]
based on the argumentPromise
: first create aPromise[T]
, then call itssuccess(value)
orfailure(exception)
method,complete(tryValule)
, orcompleteWith(aFuture)
. Usefuture
to get the created future object.
- Filtering a
Future
objectfilter
: if future is failed, thefilter
is ignore. If future is succeeded, if the filter is satisfied, return the success value, otherwise, return an exeption.withFilter
: used infor
expressioncollect partialFunction
: filter and transofrm.
- Dealing with failure
failed
: returns a new future that flips the failure and successfallbackTo
: 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 resultrecoverWith partialFunctoin
: recover with a new future when there is a match for failed resulttransform(res => ???, ex => ???)
: handle both success and failure. The pattern can be aTry
mapped toantherTry
that allows you to control the success or failure.transformWith()
: transform a future usingTry => 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 transformFuture.foldLeft
/Future.reduceLeft
: accumulates a ressult across anIterable
collection of futures.Future.sequnce
: transforms aTraversableOnce
collection of futures into a futureTraversableOnce
of values.Future.traverse
: transforms aTraversableOnce
of any element type to aTraversableOnce
of future ofTraversableOnce
of values.
Performing side-effects
foreach
: perform a side effect on success, nothing on failure. Also support thefor
loop syntaxonComplete { case Success(res) => ???; case Failure(ex) => ???}
andThen { case Success(res) => ???; case Failure(ex) => ???}
: can control the order ofandThen
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.