1
0
forked from Mirror/wren

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 :::wren
class Unicorn { class Unicorn {
prance(where, when) { 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) { prance(where) {
System.print("The unicorn prances in " + where) System.print("The unicorn prances in %(where).")
} }
prance(where, when) { 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 :::wren
class Unicorn { class Unicorn {
isFancy { true } // Unicorns are always fancy. // Unicorns are always fancy.
isFancy { true }
} }
### Setters ### Setters
@ -87,7 +88,7 @@ A setter has `=` after the name, followed by a single parenthesized parameter:
:::wren :::wren
class Unicorn { class Unicorn {
rider=(value) { 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 :::wren
class Unicorn { class Unicorn {
- { - {
System.print("Negating a unicorn is weird") System.print("Negating a unicorn is weird.")
} }
} }
@ -111,7 +112,7 @@ right-hand operand:
:::wren :::wren
class Unicorn { class Unicorn {
-(other) { -(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 :::wren
class Unicorn { class Unicorn {
[index]=(value) { [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". lets you invoke methods on "yourself".
It's an error to refer to `this` outside of a method. However, it's perfectly 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` fine to use it inside a [function][] declared *inside* a method. When you do,
still refers to the instance whose *method* is being called. `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 [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 on an object of some class, if it can't be found, it walks up the chain of
superclasses looking for it there. 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 which all other classes ultimately descend. You can specify a different parent
class using `is` when you declare the class: class using `is` when you declare the class:
:::wren :::wren
class Pegasus is Unicorn {} 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 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 (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. of the inherited built-in methods on the derived type.
The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if The metaclass hierarchy does *not* parallel the regular class hierarchy. So, if
`Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will not inherit from Pegasus inherits from Unicorn, Pegasus's metaclass does not inherit from
`Unicorn`'s metaclass. In more prosaic terms, this means that static methods Unicorn's metaclass. In more prosaic terms, this means that static methods are
are not inherited. not inherited.
:::wren :::wren
class Unicorn { 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 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 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 :::wren
var fiber = Fiber.new { var fiber = Fiber.new {
@ -36,20 +36,20 @@ a [function](functions.html).
## Invoking fibers ## Invoking fibers
Once you've created a fiber, you can invoke it (which suspends the current Once you've created a fiber, you can invoke it, which suspends the current
fiber) by calling its `call()` method: fiber, by calling its `call()` method:
:::wren :::wren
fiber.call() fiber.call()
The called fiber will execute its code until it reaches the end of its body or The called fiber executes until it reaches the end of its body or until it
until it passes control to another fiber. If it reaches the end of its body, passes control to another fiber. If it reaches the end of its body, it's
it's considered *done*: considered *done*:
:::wren :::wren
var fiber = Fiber.new { System.print("Hi") } var fiber = Fiber.new { System.print("Hi") }
System.print(fiber.isDone) //> false System.print(fiber.isDone) //> false
fiber.call() fiber.call() //> "Hi"
System.print(fiber.isDone) //> true System.print(fiber.isDone) //> true
When it finishes, it automatically resumes the fiber that called it. It's a 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 *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. 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 :::wren
var fiber = Fiber.new { var fiber = Fiber.new {
System.print("fiber 1") System.print("before yield")
Fiber.yield() Fiber.yield()
System.print("fiber 2") System.print("resumed")
} }
System.print("main 1") System.print("before call") //> before call
fiber.call() fiber.call() //> before yield
System.print("main 2") System.print("calling again") //> calling again
fiber.call() fiber.call() //> resumed
System.print("main 3") System.print("all done") //> add done
This program prints: 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
:::text the mercy of a thread scheduler playing Russian roulette with your code.
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.
## Passing values ## Passing values

View File

@ -57,7 +57,7 @@ cases.
It's also faster to execute. Since we know how many arguments are passed at 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 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 ## Getters
@ -70,19 +70,6 @@ are *getters* and have no parentheses:
1.23.sin //> 0.9424888019317 1.23.sin //> 0.9424888019317
[1, 2, 3].isEmpty //> false [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 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. 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 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() "string".count()
[1, 2, 3].clear [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 ## Setters
A getter lets an object expose a public "property" that you can *read*. 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 :::wren
person.height = 74 // Grew up! person.height = 74 // Grew up!
Despite the `=`, this is just another syntax for a method call. From the 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=(_)` 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 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 and setter with the same name without a collision. Defining both lets you
read/write properties. provide a read/write property.
## Operators ## 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 return `null` after the block has completed. If you want to return a different
value, you need an explicit `return` statement. value, you need an explicit `return` statement.
However, it's pretty common to have a method or function that just evaluates However, it's pretty common to have a method or function that just evaluates and
and returns the result of a single expression. For that, Wren has a more returns the result of a single expression. Some other languages use `=>` to
compact notation: define these. Wren uses:
:::wren :::wren
{ "single expression" } { "single expression" }
If there is no newline after the `{` (or after the parameter list in a 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 [function](functions.html)), then the block may only contain a single
expression, and it automatically returns the result of it. It's exactly the expression, and it automatically returns the result of it. It's exactly the same
same as doing: as doing:
:::wren :::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 ## Precedence and Associativity
We'll talk about Wren's different expression forms and what they mean in the We'll talk about Wren's different expression forms and what they mean in the