Methods

Return types can be inferred, but always annotate public methods.

8.1 Defining methods

Return types can be inferred, but always annotate public methods. Recursive methods require an explicit return type.

def add(a: Int, b: Int): Int = a + b

def greet(name: String): String =
  val msg = s"Hello, $name"
  msg + "!"

def log(msg: String): Unit = println(msg)

8.2 Default and named arguments

def connect(host: String = "localhost", port: Int = 8080, secure: Boolean = false): String =
  s"${if secure then "https" else "http"}://$host:$port"

connect()                          // http://localhost:8080
connect(port = 9000)               // named
connect("example.com", secure = true)

8.3 Varargs

def sum(nums: Int*): Int = nums.sum
sum(1, 2, 3)
val list = List(1, 2, 3)
sum(list*)          // spread (Scala 2: list: _*)

8.4 Multiple parameter lists (currying)

def add(a: Int)(b: Int): Int = a + b
val add5 = add(5)          // Int => Int (eta-expansion is automatic in Scala 3)
add5(10)                   // 15

def withResource[A](name: String)(body: String => A): A = body(name)
withResource("file.txt") { f =>
  s"processing $f"
}

8.5 By-name parameters

def time[A](block: => A): A =
  val start = System.nanoTime()
  val result = block                      // evaluated here, lazily
  println(s"${(System.nanoTime() - start) / 1e6} ms")
  result

time { Thread.sleep(100); 42 }

8.6 Nested methods & procedures

def factorial(n: Int): BigInt =
  def loop(n: Int, acc: BigInt): BigInt =
    if n <= 1 then acc else loop(n - 1, acc * n)
  loop(n, 1)

8.7 Infix and symbolic methods

case class Vec(x: Double, y: Double):
  def +(o: Vec): Vec = Vec(x + o.x, y + o.y)
  def *(k: Double): Vec = Vec(x * k, y * k)
  infix def dot(o: Vec): Double = x * o.x + y * o.y
  def unary_- : Vec = Vec(-x, -y)

val v = Vec(1, 2) + Vec(3, 4) * 2
val d = Vec(1, 0) dot Vec(0, 1)
val n = -v

8.8 apply & update

class Matrix(data: Array[Array[Int]]):
  def apply(i: Int, j: Int): Int = data(i)(j)
  def update(i: Int, j: Int, v: Int): Unit = data(i)(j) = v

val m = Matrix(Array.ofDim[Int](2, 2))
m(0, 1) = 5        // m.update(0, 1, 5)
m(0, 1)            // m.apply(0, 1)