scalacheat
variables |
|
var x = 5 | variable
|
GOOD val x = 5 BAD x=6 | constant
|
var x: Double = 5 | explicit type
|
functions |
|
GOOD def f(x: Int) = { x*x } BAD def f(x: Int) { x*x } | define function
hidden error: without = it’s a Unit-returning procedure; causes havoc
|
GOOD def f(x: Any) = println(x) BAD def f(x) = println(x) | define function
syntax error: need types for every arg.
|
type R = Double | type alias
|
def f(x: R) vs. def f(x: => R) | call-by-value
call-by-name (lazy parameters)
|
(x:R) => x*x | anonymous function
|
(1 to 5).map(_*2) vs. (1 to 5).reduceLeft( _+_ ) | anonymous function: underscore is positionally matched arg.
|
(1 to 5).map( x => x*x ) | anonymous function: to use an arg twice, have to name it.
|
GOOD (1 to 5).map(2*) BAD (1 to 5).map(*2) | anonymous function: bound infix method. Use 2*_ for sanity’s sake instead. |
(1 to 5).map { x => val y=x*2; println(y); y } | anonymous function: block style returns last expression.
|
(1 to 5) filter {_%2 == 0} map {_*2} | anonymous functions: pipeline style. (or parens too).
|
def compose(g:R=>R, h:R=>R) = (x:R) => g(h(x)) val f = compose({_*2}, {_-1}) | anonymous functions: to pass in multiple blocks, need outer parens.
|
val zscore = (mean:R, sd:R) => (x:R) => (x-mean)/sd | currying, obvious syntax.
|
def zscore(mean:R, sd:R) = (x:R) => (x-mean)/sd | currying, obvious syntax
|
def zscore(mean:R, sd:R)(x:R) = (x-mean)/sd | currying, sugar syntax. but then:
|
val normer = zscore(7, 0.4) _ | need trailing underscore to get the partial, only for the sugar version.
|
def mapmake[T](g:T=>T)(seq: List[T]) = seq.map(g) | generic type.
|
5.+(3); 5 + 3 (1 to 5) map (_*2) | infix sugar.
|
def sum(args: Int*) = args.reduceLeft(_+_) | varargs.
|
packages |
|
import scala.collection._ | wildcard import.
|
import scala.collection.Vector import scala.collection.{Vector, Sequence} | selective import.
|
import scala.collection.{Vector => Vec28} | renaming import.
|
import java.util.{Date => _, _} | import all from java.util except Date.
|
package pkg at start of file package pkg { ... } | declare a package.
|
data structures
|
|
(1,2,3) | tuple literal. (Tuple3 ) |
var (x,y,z) = (1,2,3) | destructuring bind: tuple unpacking via pattern matching.
|
BADvar x,y,z = (1,2,3) | hidden error: each assigned to the entire tuple.
|
var xs = List(1,2,3) | list (immutable).
|
xs(2) | paren indexing. (slides) |
1 :: List(2,3) | cons.
|
1 to 5 same as 1 until 6 1 to 10 by 2 | range sugar.
|
() (empty parens) | sole member of the Unit type (like C/Java void).
|
control constructs
|
|
if (check) happy else sad | conditional.
|
if (check) happy same as if (check) happy else () | conditional sugar.
|
while (x < 5) { println(x); x += 1} | while loop.
|
do { println(x); x += 1} while (x < 5) | do while loop.
|
import scala.util.control.Breaks._ breakable { for (x <- xs) { if (Math.random < 0.1) break } } | break. (slides) |
for (x <- xs if x%2 == 0) yield x*10 same as xs.filter(_%2 == 0).map(_*10) | for comprehension: filter/map
|
for ((x,y) <- xs zip ys) yield x*y same as (xs zip ys) map { case (x,y) => x*y } | for comprehension: destructuring bind
|
for (x <- xs; y <- ys) yield x*y same as xs flatMap {x => ys map {y => x*y}} | for comprehension: cross product
|
for (x <- xs; y <- ys) { println("%d/%d = %.1f".format(x,y, x*y)) } | for comprehension: imperative-ish
sprintf-style |
for (i <- 1 to 5) { println(i) } | for comprehension: iterate including the upper bound
|
for (i <- 1 until 5) { println(i) } | for comprehension: iterate omitting the upper bound
|
pattern matching |
|
GOOD (xs zip ys) map { case (x,y) => x*y } BAD (xs zip ys) map( (x,y) => x*y ) | use case in function args for pattern matching.
|
BAD
val v42 = 42 Some(3) match { case Some(v42) => println("42") case _ => println("Not 42") } | “v42” is interpreted as a name matching any Int value, and “42” is printed.
|
GOOD
val v42 = 42 Some(3) match { case Some(`v42`) => println("42") case _ => println("Not 42") } | ”`v42`” with backticks is interpreted as the existing val v42 , and “Not 42” is printed. |
GOOD
val UppercaseVal = 42 Some(3) match { case Some(UppercaseVal) => println("42") case _ => println("Not 42") } | UppercaseVal is treated as an existing val, rather than a new pattern variable, because it starts with an uppercase letter. Thus, the value contained within UppercaseVal is checked against 3 , and “Not 42” is printed.
|
object orientation |
|
class C(x: R) same as class C(private val x: R) var c = new C(4) | constructor params - private
|
class C(val x: R) var c = new C(4) c.x | constructor params - public
|
class C(var x: R) { assert(x > 0, "positive please") var y = x val readonly = 5 private var secret = 1 def this = this(42) } |
constructor is class body
declare a public member
declare a gettable but not settable member
declare a private member
alternative constructor
|
new{ ... } | anonymous class
|
abstract class D { ... } | define an abstract class. (non-createable)
|
class C extends D { ... } | define an inherited class.
|
class D(var x: R) class C(x: R) extends D(x) | inheritance and constructor params. (wishlist: automatically pass-up params by default)
|
object O extends D { ... } | define a singleton. (module-like)
|
trait T { ... } class C extends T { ... } class C extends D with T { ... } | traits.
interfaces-with-implementation. no constructor params. mixin-able. |
trait T1; trait T2 class C extends T1 with T2 class C extends D with T1 with T2 | multiple traits.
|
class C extends D { override def f = ...} | must declare method overrides.
|
new java.io.File("f") | create object.
|
BAD new List[Int] GOOD List(1,2,3) | type error: abstract type
instead, convention: callable factory shadowing the type
|
classOf[String] | class literal.
|
x.isInstanceOf[String] | type check (runtime)
|
x.asInstanceOf[String] | type cast (runtime)
|
x: String | ascription (compile time)
|