Skip to content

Instantly share code, notes, and snippets.

@jgeek
Last active October 20, 2020 15:20
Show Gist options
  • Save jgeek/c221b66f3b1941106e60a7cbd896a4ea to your computer and use it in GitHub Desktop.
Save jgeek/c221b66f3b1941106e60a7cbd896a4ea to your computer and use it in GitHub Desktop.
scala notes
https://booksites.artima.com/programming_in_scala_4ed/examples/
loan pattern: open a resource,operate on it, and then close the resource.
function literals, and function values
Scala supports first-class functions, which means you can express functions in
function literal syntax, i.e., (x: Int) => x + 1 ,
and that functions can be represented by objects, which are called function values.
function literals and
values is that function literals exist in the source code, whereas function val-
ues exist as objects at runtime.
Every function value is an instance of some class that extends one of several FunctionN
traits in package scala , such as Function0 for functions with no parameters, Function1 for
functions with one parameter, and so on. Each FunctionN trait has an apply method used to
invoke the function.
target typing
currying
Any time you find a control pattern repeated in multiple parts of your
code, you should think about implementing it as a new control structure.
In any method invocation in Scala in which you’repassing in exactly one argument, you can opt to use curly braces to surround
the argument instead of parentheses. println { "Hello, world!" }
uniform access principle, says that client code should not be affected by
a decision to implement an attribute as a field or method.
empty-paren methods:
it is encouraged in Scala to define methods that take no parameters and have no side effects as parameterless methods.
Subtyping: means that a value of the subclass can be used wherever a value of the superclass is required.
Scala’s two namespaces are:
• values (fields, methods, packages, and singleton objects)
• types (class and trait names)
These “accidental overrides” are the most common manifestation of what
is called the “fragile base class” problem. The problem is that if you add new
members to base classes (which we usually call superclasses) in a class hier-
archy, you risk breaking client code.
subtyping polymorphism
universal polymorphism
The reason AnyRef alias exists, instead of just using the name java.lang.Object , is
because Scala was originally designed to work on both the Java and .NET platforms. On
.NET, AnyRef was an alias for System.Object .
one use of Nothing is that it signals abnormal termination.
traits use cases: widening thin interfaces to rich ones, and defining stackable modifica-
tions.
If you plan to distribute it in compiled form, and you expect outside
groups to write classes inheriting from it, you might lean towards using an
abstract class. The issue is that when a trait gains or loses a member, any
classes that inherit from it must be recompiled, even if they have not changed.
Package objects are frequently used to
hold package-wide type aliases (Chapter 20) and implicit conversions (Chap-
ter 21)
The ensuring method takes one argument, a predicate function that takes a re-
sult type and returns Boolean , and passes the result to the predicate. If the
predicate returns true, ensuring will return the result; otherwise, ensuring
will throw an AssertionError .
Pattern matching:
Scala uses a simple lexical rule for disambiguation: a simple name starting with
a lowercase letter is taken to be a pattern variable; all other references are
taken to be constants.
You can still use a lowercase name for a pattern constant, if you need
to, by using one of two tricks. First, if the constant is a field of some ob-
ject, you can prefix it with a qualifier. For instance, pi is a variable pattern,
but this.pi or obj.pi are constants even though they start with lowercase
letters. If that does not work (because pi is a local variable, say), you can al-
ternatively enclose the variable name in back ticks. For instance, `pi` would
again be interpreted as a constant, not as a variable:
scala> E match {
case `pi` => "strange math? Pi = " + pi
case _ => "OK"
}
res14: String = OK
The only exception to the erasure rule is arrays, because they are handled
specially in Java as well as in Scala. The element type of an array is stored
with the array value, so you can pattern match on it.
def isStringArray(x: Any) = x match {
case a: Array[String] => "yes"
case _ => "no"
}
Pattern guards
This fails because Scala restricts patterns to be linear: a pattern variable may
only appear once in a pattern.
def simplifyAdd(e: Expr) = e match {
case BinOp("+", x, y) if x == y =>
BinOp("*", x, Number(2))
case _ => e
}
def describe(e: Expr): String = (e: @unchecked) match {
case Number(_) => "a number"
case Var(_)
=> "a variable"
}
Working with Lists:
Lists are quite similar to arrays, but there are two important differences.
First, lists are immutable. That is, elements of a list cannot be changed
by assignment. Second, lists have a recursive structure (i.e., a linked list), 1
whereas arrays are flat.
The list type in Scala is covariant. This means that for each pair of
types S and T , if S is a subtype of T , then List[S] is a subtype of List[T] .
For instance, List[String] is a subtype of List[Object] .
class Thermometer {
var celsius: Float = _
def fahrenheit = celsius * 9 / 5 + 32
def fahrenheit_= (f: Float) = {
celsius = (f - 32) * 5 / 9
}
override def toString = s"${fahrenheit}F/${celsius}C"
}
an initializer “ = _ ” of a field assigns a zero
value to that field. The zero value depends on the field’s type. It is 0 for
numeric types, false for booleans, and null for reference types. This is the
same as if the same variable was defined in Java without an initializer.
Note that you cannot simply leave off the “ = _ ” initializer in Scala. If
you had written:
var celsius: Float
this would declare an abstract variable, not an uninitialized one.
four kinds of abstract member: val s,var s, methods, and types.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment