Learn
Lesson 10

Lambdas

Write small functions on the spot, pass them around, and let them remember the variables around them.

A lambda is a function without a name, written right where it's needed. You've already used them with arrays: n -> n * 2 is a lambda.

Writing a lambda#

The short form is parameters, ->, and an expression. With one parameter whose type the compiler can work out, that's all you need:

main.osl
int[] numbers = [1, 2, 3, 4]
log numbers.map(n -> n * 10)
log numbers.filter(n -> n > 2)
Click the code to edit it

The compiler knows numbers holds ints, so it knows n is an int. When it can't tell, or when you want to be explicit, start the lambda with def and write the types out the same way as for a named function:

main.osl
auto add = def(int a, int b) int -> a + b
log add(2, 3)
Click the code to edit it

Lambdas with more to do#

For more than one expression, give it a block:

main.osl
auto describe = def(int n) string -> (
  if n < 0 return "negative"
  if n == 0 return "zero"
  return "positive"
)

log [-2, 0, 5].map(describe)
Click the code to edit it

Sorting by something#

sortBy takes a lambda that picks what to sort on:

main.osl
object[] people = [
  {name: "Linus", age: 54},
  {name: "Ada", age: 36},
  {name: "Grace", age: 85}
]

log people.sortBy(p -> p.age).map(p -> p.name)
log people.sortBy(p -> p.name).map(p -> p.name)
Click the code to edit it

sortBy also takes a field name as a string: people.sortBy("age").

Remembering variables#

A lambda can use the variables around the place it was written, and it keeps them even after that code has finished. This is called a closure:

main.osl
def makeCounter() def() int (
  int count = 0
  return def() int -> (
    count++
    return count
  )
)

auto next = makeCounter()
log next()
log next()
log next()

auto other = makeCounter()
log other()
Click the code to edit it

Each call to makeCounter gets its own count, and the lambda it returns holds on to it.

Functions that make functions#

Because lambdas remember their surroundings, a function can build a custom function and hand it back:

main.osl
def multiplier(int factor) def(int) int -> def(int n) int -> n * factor

auto triple = multiplier(3)
auto tenfold = multiplier(10)
log triple(7)
log tenfold(7)
log [1, 2, 3].map(triple)
Click the code to edit it

Naming function types#

A function type such as def(int) int can be named with type, which helps when it appears in several places:

main.osl
type Rule = def(string) boolean

def check(string text, Rule[] rules) boolean -> rules.every(rule -> rule(text))

Rule notEmpty = def(string s) boolean -> s.len > 0
Rule short = def(string s) boolean -> s.len <= 8

log check("osl", [notEmpty, short])
log check("much too long", [notEmpty, short])
Click the code to edit it

Async lambdas#

A lambda can run on its own thread too. Write async where def would go. Calling it returns a thread handle, and .wait() gives the value:

main.osl
auto double = async(int n) int -> n * 2
auto shout = async(string s) string (
  thread.sleep(10)
  return s.toUpper()
)

log double(4).wait()
log shout("hi").wait()
Click the code to edit it

The concurrency lesson shows them passed around and run several at a time.

Pipes#

|> passes the value on its left to the function on its right, so a chain of steps reads in the order it happens:

main.osl
def double(int n) int -> n * 2
def addOne(int n) int -> n + 1

log 5 |> double |> addOne
log addOne(double(5))
Click the code to edit it
Quick check

What does this print?

osl
auto make = def(int start) def() int (
  int n = start
  return def() int -> (
    n += 5
    return n
  )
)
auto f = make(10)
f()
log f()
Your turn

Longest word

Use sortBy with a lambda to print the words from longest to shortest.

main.osl
Ctrl Enter runs
Expected output
["banana","apple","kiwi","fig"]
0 of 24 lessons done