the types of all parameters. def factorial(n: Long): Long = // expression or block // non-recursive, result type is inferred def factorial(n: Long) = { var r = 1 for (i <- 1 to n) r = r * i r } If the function is not recursive, you need not specify the result type.
function requires more than one expression, use a block { }. def factorial(n: Long) = { // more than 1 expresions var r = 1L for (i <- 1 to n) r = r * i r // <-- last expression, compiler infers result type } The last expression of the block becomes the value that the function returns.
specify the return type. // recursive, result type has to be specified def factorial(n: Long): Long = { if (n <= 0) 1 else n * factorial(n - 1) } otherwise... // same recursive function definition without return type def factorial(n: Long) = // ... <console>:14: error: recursive method factorial needs result type else n * factorial(n - 1)
be written as tail recursive one. // recusive, tail recursive @scala.annotation.tailrec def factorial(n: Long, acc: Long = 1): Long = if (n <= 0) acc else factorial(n - 1, n * acc) Annotation @tailrec is not mandatory and just verifies that the method will be compiled with tail call optimization. <console>:15: error: could not optimize @tailrec annotated method factorial: else n * factorial(n - 1)
default arguments for functions that are used when you do not specify explicit values. def show(value: String, left: String = "(", right: String = ")"): String Call side. // uses defaults for both parameters show("Moin") // sets left in order how args are defined, right is default show("Moin", "{") // sets only right as named argument show("Moin", right = "}") // named arguments need not be in the same order as the parameters show(right = "}", left = "{", value = "Moin") Named arguments can make a function call more readable.
list can contain default arguments. import Radix._ // imports type Radix and object Decimal def add(n1: Long, rdx1: Radix = Decimal)(n2: Long, rdx2: Radix = Decimal Default arguments can be intermixed with normal ones. Normal ones still have to provided on call side. def show(prefix: String = "(", value: String, sufix: String = ")"): String show("Moin") <console>:9: error: not enough arguments for method show: (prefix: String Unspecified value parameter value. // successful forces the user to use name arguments show(value = "Moin") Convention is to use default arguments in the end of parameter list.
* behind type. def sum(ns: Int*): Int = { val _ns: Seq[Int] = ns // internaly it is Seq ... } Parameter allowing variable arguments has to be last one in parameter list. def sum(ns: Int*, n: Int): Int = ... <console>:7: error: *-parameter must come last def sum(ns: Int*, n: Int): Int = ...
any number of arguments sum() // even none If you already have a sequence of values, you cannot pass it directly to function with variable arguments. val ns = Seq(0, 1, 2, 3, 4, 5) sum(ns) // Seq cannot be used directly <console>:10: error: type mismatch; found : Seq[Int] required: Int sum(ns: _*) // successful sum( (0 to 5): _* ) // successful _* tells the compiler that you want the parameter to be expanded as a sequence of arguments.
have type parameters. def show[T](value: T): String = ... def add[F, S, R](first: F, second: S): R = ... There can be only one type parameter list for function.
place restrictions on function type parameters. def lessThan[T <: Comparable[T]](first: T, second: T): Boolean = { first.compareTo(second) < 0 } lessThan("Ahoi", "Moin") <: is called upper bounds and means that T has to be a subtype of Comparable[T].
to specify lower bounds. Expressed as >: declare a type to be a supertype of another type. case class Node[+T](h: T, t: Node[T]) { // work when Node is invariant // def prepend(elem: T): Node[T] = Node(elem, this) def prepend[U >: T](elem: U): Node[U] = Node(elem, this) } Typical usage is when type parameter of enclosing class is covariant.
have both bounds for one type parameter. T <: Upper >: Lower But ... it is not possible to have multiple upper or lower bounds. It is still possible to require that type parameter implements multiple traits. T <: Comparable[T] with Serializable with Clonable
as implicit. sealed trait Affix case class Prefix(value: String) extends Affix case class Sufix(value: String) extends Affix def show(value: String)(implicit prefix: Prefix, sufix: Sufix): String Function can still be called with explicit arguments... show("Moin")(Prefix("("), Sufix(")"))
for default values to supply with the function call. object Affixes { implicit val prefix = Prefix("(") implicit def sufix = Sufix(")") } import Affixes._ // i.e. import of implicit values show("Moin") Default value has to be val or def declared as implicit. Usual implicits resolution mechanism is applied.
parameter there is a syntactic sugar called context bound. // suppose that Prefix uses type parameter for value case class Prefix[T](value: T) extends Affix // generic definition of show will look like def show[T](value: T)(implicit prefix: Prefix[T]): String = { prefix.value // accessing implicit parameter, directly ... } // shorthand version defined via context bound def show[T : Prefix](value: T): String = { val prefix = implicitly[Prefix[T]] // retrieving implicit parameter prefix.value // accessing implicit parameter ... } Context bound is important concept by encoding type classes in scala.
for one type parameter T. case class Prefix[T](value: T) extends Affix case class Sufix[T](value: T) extends Affix def show[T : Prefix : Sufix](value: T): String = ... def show[T <: Comparable[T] : Prefix : Sufix](value: T): String = ... If more than 1 type parameter is required, context bounds cannot be used. case class Infix[T1, T2](left: T1, right: T2) extends Affix // def show[T1, T2 : Infix] won't compile def show[T1, T2](left: T1, right: T2)(implicit infix: Infix[T1, T2]):
is to contraint type parameters. // usage def show[T](value: T)(implicit ev: T =:= String): String = ... // call side show("Moin") show(1) <console>:17: error: Cannot prove that Int =:= String. show(1) A =:= B, which means A must be equal to B A <:< B, which meand A must be subtype of B
annonymous functions. (x: Int) => x + 1 It is called function literal. val addOne = (x: Int) => x + 1 // assignment to variable Just like numbers or strings have literals: 3 or "Moin", functions have too.
will convert it into annonymous class definition. val addOne = new Function1[Int, Int] { def apply(x: Int): Int = x + 1 // special rule for apply } addOne(2) addOne.apply(2) Provided are traits from Function0 until Function22. // compiled into Function2[Int, String, String] (x: Int, y: String) => x + "-" + y // compiled into Function0[String] () => "Moin"
other fuctions as parameters or return them as results. // function as parameter def fiftyPercent(fn: Double => Double): Double = fn(0.5) // function as result def multiplyBy(factor: Int) = (x: Int) => x * factor // supplying function as argument fiftyPercent( (x: Double) => x * x ) val twice = multiplyBy(2) // assignment to variable twice(2) // call Such functions are called high-order functions. Syntax Double => Double represents function type which can be used as parameter type or result type.
another function, Scala deduces types when possible. def fiftyPercent(fn: Double => Double): Double = fn(0.5) fiftyPercent( (x: Double) => x * x ) fiftyPercent( (x) => x * x ) // type is inferred to be Double fiftyPercent( x => x * x ) // parens can be omitted For function with 1 parameter it is possible to omit ().
parameters too. def dropWhile[A](l: List[A], f: A => Boolean): List[A] = ... val numbers = List(1, 2, 3) dropWhile(numbers, (x: Int) => x < 2) // Int is required Type parameters are inferred from le to right across parameter lists. def dropWhile[A](l: List[A])(f: A => Boolean): List[A] = ... val numbers = List(1, 2, 3) dropWhile(numbers, x => x < 2) To help compiler use multiple parameter lists.
package, class, object or even in another function. In body of function it is possible to access any variables from an enclosing scope. def show(items: List[String], sufix: String): String = { // inner function, which accesses sufix from enclosing scope def loop(items: List[String], buffer: StringBuilder) = if (items.isEmpty) buffer else { buffer.append(head).append(sufix) loop(items.tail, buffer) } loop(items, StringBuilder.newBuilder).toString } Such function which access variables from enclosing scope is called closure.
That means applying some but not all the arguments of the function. // helper which applies A in any (A, B) => C function def partial[A, B, C](a: A, fn: (A, B) => C): B => C = (b: B) => fn(a, b) val multiply = (x: Int, y: Int) => x * y // partialy applied multiply, to always multiply by 2 val doubled = partial(2, multiply) doubled: Int => Int = $$Lambda$1197/1032689422@2fac80a8 The process is called partial application and result is partially applied function.
dedicated syntax for that. def divide(x: Int, y: Int): Int = x / y val oneByN = divide(1, _: Int) // applying 1st argument oneByN: Int => Int = $$Lambda$1336/1775639151@2696b687 val nBy100 = divide(_: Int, 100) // applying 2nd argument nBy100: Int => Int = $$Lambda$1337/1973093841@ea45a5b _: Type represents "hole", yet not applied argument.
defined function as value. def divide(x: Int, y: Int): Int = x / y // Not applying any of the arguments val division = divide(_: Int, _: Int) val division = divide _ // shorter way Technically we are converting method into instance of Function object.
of one-parameter functions and vice versa. // helper which transforms (A, B) => C into A => B => C def curry[A, B, C](fn : (A, B) => C): A => B => C = (a: A) => (b: B) => fn(a, b) // helper which transforms A => B => C into (A, B) => C def uncurry[A, B, C](fn: A => B => C): (A, B) => C = (a: A, b: B) => fn(a)(b) val multiply = (x: Int, y: Int) => x * y val multiplyChain = curry(multiply) // Int => Int => Int val againMultiply = uncurry(multiplyChain) multiplyChain(2)(3) val doubled = multiplyChain(2) // partially applied function
application. def divide(x: Int, y: Int): Int = x / y val multiply = (x: Int, y: Int) => x * y val oneByN = (divide _).curried(1) // divide(1, _: Int) oneByN: Int => Int = $$Lambda$1336/1775639151@2696b687 val twice = multiply.curried(2) // multiply(2, _: Int) twice: Int => Int = scala.Function2$$Lambda$1411/1255024717@236861da curried is provided by all Function* traits.
// helper which composes two functions def compose[A, B, C](f: A => B, g: B => C): A => C = (a: A) => g(f(a)) val addOne = (x: Int) => x + 1 val multiplyBy100 = (x: Int) => x * 100 val plus1Muliplied100 = compose(addOne, multiplyBy100) It composes 2 functions A => B and B => C into A => B. Types of the functions must be in alignment.
Scala standard library provides methods for function composition. val addOne = (x: Int) => x + 1 val multiplyBy100 = (x: Int) => x * 100 val plus1Muliplied100 = addOne.andThen(multiplyBy100) val multiply100plus1 = addOne.compose(multiplyBy100) They are only defined in trait Function1, thus function with more parameters must be curried first.
about total and partial functions. // total function, defined for each Int def addOne(i: Int) = i + 1 // partial function, undefined for 0 def divideOne(d: Int) = 1 / d
is partial function. // another form of annonymous function val divideOne: PartialFunction[Int, Int] = { case d: Int if d != 0 => 42 / d } // it is translated into (more or less) val divideOne = new PartialFunction[Int, Int] { def apply(d: Int) = 1 / d def isDefinedAt(d: Int) = d != 0 } PartialFunction is trait which extends Function1
= { case '+' => 1 case '-' => -1 } // application like total function scala> plusMinus('+') res15: Int = 1 scala> plusMinus('o') // undefined scala.MatchError: o (of class java.lang.Character) at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:254) // check if defined scala> plusMinus.isDefinedAt('0') res16: Boolean = false
call where Function1 is expected someMap.foreach { // ... destructuring for free case (k, v) => println(k + " -> " + v) } case class Greeting(greeting: String) List(Greeting("Moin"), Int).collect { case Greeting(greeting) => println(greeting) greeting } Pattern matching like casting-done-right, guards, and destructuring for free.
be modeled as function with no parameters. // code parameter has type `Function0` def runInThread(code: () => Unit): Thead = { ... code() ... } // you have to supply function () => Unit runInThread(() => println("Moin"))
called by value, i.e. value of the parameter is evaluated before it is given to function. // call by name parameter def runInThread(code: => Unit): Thread = ... // no need for () runInThread(println("Moin")) => before paremeter type says compiler that parameter is called by name. Its value is not evaluated before it is given to function. It is considered lazy on call side.
by name parameter happens everytime the parameter is accessed. def until(condition: => Boolean)(code: => Unit): Unit = { while(!condition) { // evaluated by aech access code // no parens necessary } } var x = 0 until(x == 10)({ x += 1; println(x) }) // loop is terminated
of ( ) for any parameter list with just one parameter. def until(condition: => Boolean)(code: => Unit): Unit = { while(!condition) { // evaluated by aech access code // no parens necessary } } var x = 0 until (x == 10) { x += 1 println(x) } until { x == 20 } { x += 1; println(x) } This allows to write control abstractions, i. e. functions which looks like build in language keywords.
value from an anonymous function. def indexOf(str: String, ch: Char): Int = { var i = 0 until (i == str.length) { // closure // will return from enclosing functions if (str(i) == ch) return i i += 1 } return -1 } indexOf("Moin", 'o') res8: Int = 1
is used in a named function it has to provide result type. scala> def show(value: String, sufix: String = "") = { return value + sufix } <console>:11: error: method show has return statement; needs result type def show(value: String, sufix: String = "") = { return value + sufix } Very fragile construct. // return expression is captured and not evaluated def somewhereDeepInTheCodebase: () => Int = () => return () => 1 // passed thru a lot of code val x = somewhereDeepInTheCodebase // finally used x() scala.runtime.NonLocalReturnControl // !!! RESULT !!! // Btw. NonLocalReturnControl extends NoStackTrace // i.e. so you are given no clue about origin.
as a valid expression for any Single Abstract Method (SAM) type scala> val r: Runnable = () => println("Run!") r: Runnable = $$Lambda$1073/754978432@7cf283e1 scala> r.run()
to SAM type instances, not arbitrary expressions of FunctionN. scala> val f = () => println("Faster!") scala> val fasterRunnable: Runnable = f <console>:12: error: type mismatch; found : () => Unit required: Runnable
compiled to SAM interfaces. scala> val addOne = (n: Int) => n + 1 addOne: Int => Int = $$Lambda$1342/671078904@642c6461 scala> val addTwo = (n: Int) => n + 3 addTwo: Int => Int = $$Lambda$1343/205988608@5f6494c0 scala> addOne andThen addTwo res14: Int => Int = scala.Function1$$Lambda$1335/1630903943@464aeb09
expression can be omitted even when the invoked method is overloaded. scala> trait MyFun { def apply(x: Int): String } scala> object T { | def m(f: Int => String) = 0 | def m(f: MyFun) = 1 | } scala> T.m(x => x.toString) res0: Int = 0 Note that though both methods are applicable, overloading resolution selects the one with the Function1 argument type.
prefer methods with Function-typed arguments over methods with parameters of SAM types. scala> object T { | def m(f: () => Unit) = 0 | def m(r: Runnable) = 1 | } scala> val f = () => () scala> T.m(f) res0: Int = 0 In Scala 2.11, the first alternative was chosen because it is the only applicable. In Scala 2.12, both methods are applicable, but most specific alternative is picked.
{ def i(): Int } implicit def convert(fun: () => Int): MySam = new MySam { def i() = 1 } val sam1: MySam = () => 2 // Uses SAM conversion, not the implicit sam1.i() // Returns 2 Note that SAM conversion only applies to lambda expressions, not to arbitrary expressions with Scala FunctionN types val fun = () => 2 // Type Function0[Int] val sam2: MySam = fun // Uses implicit conversion sam2.i() // Returns 1