Edit docs. Docs docs docs.

This commit is contained in:
Bob Nystrom
2017-10-19 19:52:05 -07:00
parent f8076c2c1c
commit e043a95e4e
4 changed files with 82 additions and 66 deletions

View File

@ -39,7 +39,7 @@ their names inside the parentheses:
:::wren
class Unicorn {
prance(where, when) {
System.print("The unicorn prances in " + where + " at " + when)
System.print("The unicorn prances in %(where) at %(when).")
}
}
@ -55,11 +55,11 @@ define multiple methods with the same name:
}
prance(where) {
System.print("The unicorn prances in " + where)
System.print("The unicorn prances in %(where).")
}
prance(where, when) {
System.print("The unicorn prances in " + where + " at " + when)
System.print("The unicorn prances in %(where) at %(when).")
}
}
@ -77,7 +77,8 @@ A getter leaves off the parameter list and the parentheses:
:::wren
class Unicorn {
isFancy { true } // Unicorns are always fancy.
// Unicorns are always fancy.
isFancy { true }
}
### Setters
@ -87,7 +88,7 @@ A setter has `=` after the name, followed by a single parenthesized parameter:
:::wren
class Unicorn {
rider=(value) {
System.print("I am being ridden by " + value)
System.print("I am being ridden by %(value).")
}
}
@ -101,7 +102,7 @@ Prefix operators, like getters, have no parameter list:
:::wren
class Unicorn {
- {
System.print("Negating a unicorn is weird")
System.print("Negating a unicorn is weird.")
}
}
@ -111,7 +112,7 @@ right-hand operand:
:::wren
class Unicorn {
-(other) {
System.print("Subtracting " + other + " from a unicorn is weird")
System.print("Subtracting %(other) from a unicorn is weird.")
}
}
@ -138,7 +139,7 @@ operator and a setter:
:::wren
class Unicorn {
[index]=(value) {
System.print("You can't stuff " + value + " into me at " + index)
System.print("You can't stuff %(value) into me at %(index)!")
}
}
@ -181,8 +182,20 @@ always refers to the instance whose method is currently being executed. This
lets you invoke methods on "yourself".
It's an error to refer to `this` outside of a method. However, it's perfectly
fine to use it inside a [function][] contained in a method. When you do, `this`
still refers to the instance whose *method* is being called.
fine to use it inside a [function][] declared *inside* a method. When you do,
`this` still refers to the instance whose *method* is being called:
:::wren
class Unicorn {
name { "Francis" }
printNameThrice() {
(1..3).each {
// Use "this" inside the function passed to each().
System.print(this.name) //> Francis
} //> Francis
} //> Francis
}
[function]: functions.html
@ -435,14 +448,14 @@ A class can inherit from a "parent" or *superclass*. When you invoke a method
on an object of some class, if it can't be found, it walks up the chain of
superclasses looking for it there.
By default, any new class inherits from `Object`, which is the superclass from
By default, any new class inherits from Object, which is the superclass from
which all other classes ultimately descend. You can specify a different parent
class using `is` when you declare the class:
:::wren
class Pegasus is Unicorn {}
This declares a new class `Pegasus` that inherits from `Unicorn`.
This declares a new class Pegasus that inherits from Unicorn.
Note that you should not create classes that inherit from the built-in types
(Bool, Num, String, Range, List). The built-in types expect their internal bit
@ -450,9 +463,9 @@ representation to be very specific and get horribly confused when you invoke one
of the inherited built-in methods on the derived type.
The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if
`Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from
`Unicorn`'s metaclass. In more prosaic terms, this means that static methods
are not inherited.
Pegasus inherits from Unicorn, Pegasus's metaclass does not inherit from
Unicorn's metaclass. In more prosaic terms, this means that static methods are
not inherited.
:::wren
class Unicorn {

View File

@ -23,7 +23,7 @@ fiber for every line of code you type in.
All Wren code runs within the context of a fiber. When you first start a Wren
script, a main fiber is created for you automatically. You can spawn new fibers
using the `Fiber` class's constructor:
using the Fiber class's constructor:
:::wren
var fiber = Fiber.new {
@ -36,20 +36,20 @@ a [function](functions.html).
## Invoking fibers
Once you've created a fiber, you can invoke it (which suspends the current
fiber) by calling its `call()` method:
Once you've created a fiber, you can invoke it, which suspends the current
fiber, by calling its `call()` method:
:::wren
fiber.call()
The called fiber will execute its code until it reaches the end of its body or
until it passes control to another fiber. If it reaches the end of its body,
it's considered *done*:
The called fiber executes until it reaches the end of its body or until it
passes control to another fiber. If it reaches the end of its body, it's
considered *done*:
:::wren
var fiber = Fiber.new { System.print("Hi") }
System.print(fiber.isDone) //> false
fiber.call()
fiber.call() //> "Hi"
System.print(fiber.isDone) //> true
When it finishes, it automatically resumes the fiber that called it. It's a
@ -66,34 +66,24 @@ Things get interesting when a fiber *yields*. A yielded fiber passes control
*back* to the fiber that ran it, but *remembers where it is*. The next time the
fiber is called, it picks up right where it left off and keeps going.
You can make a fiber yield by calling the static `yield()` method on `Fiber`:
You make a fiber yield by calling the static `yield()` method on Fiber:
:::wren
var fiber = Fiber.new {
System.print("fiber 1")
System.print("before yield")
Fiber.yield()
System.print("fiber 2")
System.print("resumed")
}
System.print("main 1")
fiber.call()
System.print("main 2")
fiber.call()
System.print("main 3")
System.print("before call") //> before call
fiber.call() //> before yield
System.print("calling again") //> calling again
fiber.call() //> resumed
System.print("all done") //> add done
This program prints:
:::text
main 1
fiber 1
main 2
fiber 2
main 3
Note that even though this program has *concurrency*, it's
still *deterministic*. You can reason precisely about what it's doing and
aren't at the mercy of a thread scheduler playing Russian roulette with your
code.
Note that even though this program uses *concurrency*, it is still
*deterministic*. You can reason precisely about what it's doing and aren't at
the mercy of a thread scheduler playing Russian roulette with your code.
## Passing values

View File

@ -57,7 +57,7 @@ cases.
It's also faster to execute. Since we know how many arguments are passed at
compile time, we can compile this to directly call the right method and avoid
any "if I got two arguments do this..." logic.
any "if I got two arguments do this..." runtime work.
## Getters
@ -70,19 +70,6 @@ are *getters* and have no parentheses:
1.23.sin //> 0.9424888019317
[1, 2, 3].isEmpty //> false
Sometimes you have a method that doesn't need any parameters, but modifies the
object or has some other side effect. For those, it's better to use empty
parentheses:
:::wren
list.clear()
Also, when a method supports multiple arities, it's typical to include the `()`
in the zero-argument case to be consistent with the other versions:
Fiber.yield()
Fiber.yield("value")
A getter is *not* the same as a method with an empty argument list. The `()` is
part of the signature, so `count` and `count()` have different signatures.
Unlike Ruby's optional parentheses, Wren wants to make sure you call a getter
@ -92,21 +79,39 @@ like a getter and a `()` method like a `()` method. These don't work:
"string".count()
[1, 2, 3].clear
If you're defining some member that doesn't need any parameters, you need to
decide if it should be a getter or a method with an empty `()` parameter list.
The general guidelines are:
* If it modifies the object or has some other side effect, make it a method:
:::wren
list.clear()
* If the method supports multiple arities, make the zero-parameter case a `()`
method to be consistent with the other versions:
:::wren
Fiber.yield()
Fiber.yield("value")
* Otherwise, it can probably be a getter.
## Setters
A getter lets an object expose a public "property" that you can *read*.
Likewise, a *setter* let you write to a property:
Likewise, a *setter* lets you write to a property:
:::wren
person.height = 74 // Grew up!
Despite the `=`, this is just another syntax for a method call. From the
language's perspective, the above line is just a call to the `height=(_)`
method, passing in `74`.
method on `person`, passing in `74`.
Since the `=(_)` is in the setter's signature, an object can have both a getter
and setter with the same name without a collision. This way, you can have
read/write properties.
and setter with the same name without a collision. Defining both lets you
provide a read/write property.
## Operators

View File

@ -107,17 +107,17 @@ Blocks of this form when used for method and function bodies automatically
return `null` after the block has completed. If you want to return a different
value, you need an explicit `return` statement.
However, it's pretty common to have a method or function that just evaluates
and returns the result of a single expression. For that, Wren has a more
compact notation:
However, it's pretty common to have a method or function that just evaluates and
returns the result of a single expression. Some other languages use `=>` to
define these. Wren uses:
:::wren
{ "single expression" }
If there is no newline after the `{` (or after the parameter list in a
[function](functions.html)), then the block may only contain a single
expression, and it automatically returns the result of it. It's exactly the
same as doing:
expression, and it automatically returns the result of it. It's exactly the same
as doing:
:::wren
{
@ -136,6 +136,14 @@ put a newline in there:
}
}
Using an initial newline after the `{` does feel a little weird or magical, but
newlines are already significant in Wren, so it's not totally crazy. The nice
thing about this syntax as opposed to something like `=>` is that the *end* of
the block has an explicit delimiter. That helps when chaining:
:::wren
numbers.map {|n| n * 2 }.where {|n| n < 100 }
## Precedence and Associativity
We'll talk about Wren's different expression forms and what they mean in the