1
0
forked from Mirror/wren
Files
wren/doc/site/functions.markdown

126 lines
4.6 KiB
Markdown
Raw Normal View History

2014-01-30 06:51:52 -08:00
^title Functions
2014-04-14 21:23:46 -07:00
^category types
2014-01-30 06:51:52 -08:00
2014-04-04 20:45:12 -07:00
No self-respecting language today can get by without functions—first class little bundles of code. Since Wren is object-oriented, most of your code will live in methods on classes, but free-floating functions are still useful.
Functions are objects like everything else in Wren, instances of the `Fn` class.
## Creating functions
Most of the time you create a function just to pass it to some method. For example, if you want to filter a [list](lists.html) by some criteria, you'll call its `where` method, passing in a function that defines the predicate you're filtering on.
2014-04-07 21:03:16 -07:00
Since that's the most common usage pattern, Wren's syntax optimizes for that. Taking a page from Ruby, a function is created by passing a *block argument* to a method. At it's simplest, it looks like this:
2014-04-04 20:45:12 -07:00
:::dart
blondie.callMe {
IO.print("This is the body!")
}
Here we're invoking the `callMe` method on `blondie`. We're passing one argument, a function whose body is everything between that pair of curly braces.
2014-04-07 21:03:16 -07:00
Methods that take a block argument receive it as a normal parameter. `callMe` could be defined like so:
2014-04-04 20:45:12 -07:00
:::dart
class Blondie {
callMe(fn) {
// Call it...
}
}
A method can take other arguments in addition to the block. They appear before the block just like a regular argument list. For example:
:::dart
blondie.callMeAt(867, 5309) {
IO.print("This is the body!")
}
Of course, you don't *have* to use a block argument to pass a function to a method. If you already have a function object, you can pass it like a regular argument:
:::dart
var someFn = // Get a function...
blondie.callMe(someFn)
Block arguments are purely sugar for creating a function and passing it in one little blob of syntax. There are some times when you want to create a function but *don't* need to pass it to a method. For that, you can call the `Fn` class's constructor:
2014-04-14 21:23:46 -07:00
:::dart
2014-04-04 20:45:12 -07:00
var someFn = new Fn {
IO.print("Hi!")
}
2014-04-07 21:03:16 -07:00
As you can see it takes a block argument too! All the constructor does it return that, so this exists purely as a convenience method for you.
2014-04-04 20:45:12 -07:00
## Calling functions
Once you have a function, how do you invoke it? Like everything in Wren, you do so by calling a method on it:
:::dart
class Blondie {
callMe(fn) {
fn.call
}
}
Functions expose a `call` method that executes the body of the function. Of course, this is dynamically-dispatched like other methods, so you can define your own "function-like" classes and pass them to methods that expect real functions.
:::dart
class FakeFn {
call {
IO.print("I'm feeling functional!")
}
}
blondie.callMe(new FakeFn)
## Function parameters
2014-04-07 21:03:16 -07:00
Of course, functions aren't very useful if you can't pass values to them. The functions that we've seen so far take no parameters. To change that, you can provide a parameter list surrounded by `|` immediately after the opening brace of the body, like so:
:::dart
blondie.callMe {|first, last|
IO.print("Hi, " + first + " " + last + "!")
}
Here we're passing a function to `greet` that takes two parameters, `first` and `last`. They are passed to the function when it's called:
:::dart
class Blondie {
callMe(fn) {
fn.call("Debbie", "Harry")
}
}
It's an error to call a function with fewer or more arguments than its parameter list expects.
## Returning values
2014-04-20 21:42:17 -07:00
The body of a function is a [block](syntax.html#blocks). If it is a single expression—more precisely if there is no newline after the `{` or parameter list—then the function implicitly returns the value of the expression.
2014-04-07 21:03:16 -07:00
Otherwise, the body returns `null` by default. You can explicitly return a value using a `return` statement. In other words, these two functions do the same thing:
:::dart
new Fn { "return value" }
new Fn {
return "return value"
}
2014-04-04 20:45:12 -07:00
## Closures
As you expect, functions are closures: they can access variables defined outside of their scope. They will hold onto closed-over variables even after leaving the scope where the function is defined:
:::dart
class Counter {
static create {
var i = 0
return new Fn { i = i + 1 }
}
}
Here, the `create` method returns the function created on its second line. That function references a variable `i` declared outside of the function. Even after the function is returned from `create`, it is still able to access `i`.
:::dart
var counter = Counter.create
IO.print(counter.call) // Prints "1".
IO.print(counter.call) // Prints "2".
IO.print(counter.call) // Prints "3".