// mutable value/reference
var variable = ...
// immutable value/reference aka constant
// calculated only ONCE
val value = ...
// method
def method(p: Type) = ??? // TODO
// ~constant
lazy val cached = ...
// type inference
val num: Int = 5
val num = 5
5.toString() // or "5.toString" or "5 toString"
// "operators"
1 + 2
1.+(2)
// no ternary operator
// yup? "Yep": "Nope"
val isIt2 = if(yup) "Yep" else "Nope"
// first? "Yep": (second? "Nope": "Maybe")
val isIt4 = if(first) "Yep" else if(second) "Nope" else "Maybe"
class MyClass1
class MyClass2(x: Int) // constructor
class MyClass3(val x: Int, var y: Int) // fields
class MyClass4(x: Int, y: Int = 3) {
def aMethod = x + y // method
}
new MyClass4(1, 2) // regular
new MyClass4(5) // using default params
new MyClass4(y=7, x=3) // named params
// multiple classes per file, generics, traits, abstract types ...
object StringUtils {
def trim(str: String): String = ...
}
// static factory methods
object MyClass {
def apply(param1: String) = new MyClass(param1)
}
val mc1 = new MyClass("ABC") // can't change to subclass later
val mc2 = MyClass("DEF") // desugars to MyClass.apply
val fruits = List("apple", "orange")
implicit class StringOps(str: String) {
def firstCaps: String = {
if (str.isEmpty) str
else str(0).toUpper + str.drop(1)
}
}
println("whatever".firstCaps) // Whatever
If it walks like a duck and it quacks like a duck,
it might be a turkey wrapped in a duck adapter.
def doQuack(quackable: { def quack: String }) =
println(quackable.quack)
class Duck {
def quack: String = "Quack, quack!"
}
doQuack(new Duck) // Quack, quack!
// type Ducky = { def quack: String }
// def doQuack(quackable: Ducky) =
I don't care if it is a field or a method! Same code. :)
class Person {
var age = 0
}
// same as:
class Person {
private var privateAge = 0
def age = privateAge // getter
def age_=(newValue: Int) { // setter
if (newValue > privateAge) privateAge = newValue
}
}
val nums = List(1, 2, 3)
val numsPlus1 = nums.map ( x => x + 1 )
val numsPlus2 = nums.map { x => x + 2 }
val numsPlus3 = nums.map (_ + 3)
val plus4 = (x: Int) => x + 4
val numsPlus4 = nums.map(plus4)
val numsPlus5 = for (x <- nums) yield x + 5
// functional - declarative
val sum = nums.foldLeft(0) { (acc, x) =>
acc + x
}
// imperative - boring, error prone
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
// ADT (Algebraic Data Types)
sealed trait Animal { def name: String }
case class Cat(name: String) extends Animal
case class Dog(name: String, weight: Int) extends Animal
val pet: Animal = Dog("Fido", 7)
val petStatement = pet match {
case Cat(name) => s"$name says meow!"
case Dog(name, weight) if (weight < 2) => s"$name says yip!"
case Dog(name, weight) => s"$name says bark!"
}
println(petStatement)
def myMethod(x: Int, ctx: AlwaysPresentContext) ...
myMethod(1, ctx)
myMethod(2, ctx) ...
// much better :)
def myMethod(x: Int)(implicit ctx: AlwaysPresentContext)
implicit val ctx = new AlwaysPresentContext
myMethod(1)
myMethod(2)
Similar, but far more powerful than Java/C# annotations
Scala programmer waits for project to build