mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 14:18:42 +01:00
Start documenting functions.
This commit is contained in:
@ -1,3 +1,98 @@
|
||||
^title Functions
|
||||
|
||||
**TODO**
|
||||
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.
|
||||
|
||||
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:
|
||||
|
||||
:::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.
|
||||
|
||||
Methods that receive a block argument take as a normal parameter. `callMe` could be defined like so:
|
||||
|
||||
:::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:
|
||||
|
||||
var someFn = new Fn {
|
||||
IO.print("Hi!")
|
||||
}
|
||||
|
||||
As you can see it takes a block argument too! All the constructor does it return that, so there's no special syntax here.
|
||||
|
||||
## 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
|
||||
|
||||
**TODO**
|
||||
|
||||
**TODO: Implicit returns from short bodies.**
|
||||
|
||||
## 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".
|
||||
|
||||
Reference in New Issue
Block a user