Scala Explained!

Scala tips and code snippets.

Functions

A function is a block of code that can be called. Scala support a wide range of function related features including anonymous functions, higher order functions, currying, etc…

That is why Scala is a great language for functional programming.

Defined functions

A function can be explicitly defined using the keyword def. The defined function can take zero to many parameters and it can return zero to one value.

Functions parameters with default values

You can set default values to function parameters. The function can then be called without giving a value to these parameters.

Example:

// Display a workflow.

// `workflow` function has 2 parameters `something` and `somewhere`
// that have a default value
def workflow(
    item: String,
    something: String = "clean",
    otherThing: String,
    somewhere: String = "memory"): Unit =
  println(
    s"take $item, do $something and $otherThing then store into $somewhere")

workflow("a value", otherThing = "reverse")
// --> take a value, do clean and reverse then store into memory

Anonymous functions

A function can be create on the fly without the keyword def. This kind of function is called an anonymous function or a lambda function:

// Double a value.

// create an anonymous function that multiplies a value by two
val computeDouble = (x: Int) => x * 2

// call the function
val result = computeDouble(22)

println(result)
// --> 44

An anonymous function can take zero to several parameters.

Anonymous functions can take up to 22 parameters.

Currying

Anonymous functions can be defined with a shortened syntax using underscore _ symbol. The _ is placed where a parameter of the function is used. That is called currying.

Here is an example with a function divideByFour written with and without currying:

// Divide a given number by four.

// no currying here
val divideByFourWithoutCurrying: Int => Int = (x) => x / 4

// currying used to replace the parameter `x`
val divideByFourWithCurrying: Int => Int = _ / 4

val x = divideByFourWithoutCurrying(24)
val y = divideByFourWithCurrying(24)

println(s"${ if (x == y) "same value" else "different values" }")
// --> same value

Higher order functions

A higher order function is a function that takes an other function as a parameter, or returns a function as a return value.

Scala API proposes a large set of higher order functions for various uses.

For example the map method of a collection instance applies a given function to all the elements inside the collection and returns a new collection that contains the result of the operation:

// Capitalize first names.

val names = List("kader", "sakura")

// call the higher order function `map` with a curried function as an argument
val capitalized = names.map(_.capitalize)

println(capitalized.mkString(" & "))
// --> Kader & Sakura

Functions with multiple parameter lists

In Scala functions can take multiple parameter lists. This allows syntactic shortcuts like partial parameter application.

Partial functions

It is easy to create partial functions from a multiple parameter lists function using currying or type conversion.

Functions with a variable number of parameters

Functions with a variable number of parameters can be defined by adding * after the type of the parameter that will be repeated. These function are sometimes called variadic functions.

It is also possible to send a list of values as arguments to a variadic function by expanding the argument list with : _* symbol.

// Print status messages.

// define a variadic function, the parameter `items` will receive the
// arguments list
def prettyPrint(items: String*): Unit = items.foreach(println)

// call `prettyPrint` with some arguments
prettyPrint("download started", "downloading", "failed")
// --> download started
// --> downloading
// --> failed

val states = List("restarted", "finished")

// call `prettyPrint` by expanding an arguments list
prettyPrint(states: _*)
// --> restarted
// --> finished

Polymorphic functions

Polymorphic functions are generic functions whose arguments type or return value type is a type variable.

The type variables are replaced by a concrete types when the function is called. The concrete types are inferred from the parameters or the return type.

// Format a list of values using a dot as separator.

// `dot` is a generic function that uses a type variable `A`,
// `dot` also has a variable number of parameters
def dot[A](items: A*): String = items.mkString(".")

// `A` becomes `String` because the arguments are `String` values
val hostname = dot("www", "example", "org")

println(hostname)
// --> www.example.org

// `A` becomes `Int` because the arguments are `Int` values
val ipAddress = dot(127, 0, 0, 1)

println(ipAddress)
// --> 127.0.0.1

By-name parameters

By name parameters are function parameters that are evaluated every time they are used. If they are never used they will never be evaluated:

// Repeat a statement a defined number of times.

// runs `block` by name parameter a multiple number of times
def repeat(times: Int)(block: => Unit): Unit =
  (0 until times).foreach(_ => block)

repeat(3) {
  val status = "task ongoing..."
  println(s"status: $status")
}
// --> status: task ongoing...
// --> status: task ongoing...
// --> status: task ongoing...
You can leave a comment or request changes here.

This project is maintained by Y. Somda (yoeo)
Logo by Icon Island — theme by orderedlist — remixed by yoeo