Docs for operators and some other stuff.

This commit is contained in:
Bob Nystrom
2014-04-08 21:18:17 -07:00
parent 3a55acfe1a
commit b2941cbbb6
5 changed files with 70 additions and 9 deletions

View File

@ -21,7 +21,7 @@ The simplest branching statement, `if` lets you conditionally skip a chunk of co
:::wren
if (ready) IO.print("go!")
That evaluates the parenthesized expression after `if`. If it's true, then the statement after the condition is evaluated. Otherwise it is skipped. Instead of a statement, you can have a block:
That evaluates the parenthesized expression after `if`. If it's true, then the statement after the condition is evaluated. Otherwise it is skipped. Instead of a statement, you can have a [block](syntax.html#blocks):
:::wren
if (ready) {

View File

@ -1,7 +1,5 @@
^title Classes
**TODO: Refactor `method-calls` and `classes` into using and creating classes.**
Every value in Wren is an object, and every object is an instance of a class.
Even `true` and `false` are full-featured objects—instances of the `Bool` class.
@ -55,10 +53,6 @@ Unlike most other dynamically-typed languages, in Wren you can have multiple met
When you [call](method-calls.html) the `prance` method, it selects the right one based on how many arguments you pass it.
**TODO: Defining operators and setters.**
**TODO: `static` methods.**
## Constructors
To create a new instance of a class, you use the `new` keyword. We can make a unicorn like so:
@ -68,14 +62,16 @@ To create a new instance of a class, you use the `new` keyword. We can make a un
You almost always want to define some state or do some other initialization on a new object. For that, you'll want to define a constructor, like so:
:::dart
class Unicorn {
new {
IO.print("I am a constructor!")
}
}
When you create an instance with `new`, its constructor will be invoked. Like methods, you can pass arguments to the constructor by adding a parenthesized parameter list after `new`:
When you create an instance with `new`, its constructor will be invoked. It's just a method with a special name. Like methods, you can pass arguments to the constructor by adding a parenthesized parameter list after `new`:
:::dart
class Unicorn {
new(name, color) {
IO.print("My name is " + name + " and I am " + color + ".")
@ -84,8 +80,47 @@ When you create an instance with `new`, its constructor will be invoked. Like me
Values are passed to the constructor like so:
:::dart
new Unicorn("Flicker", "purple")
Like other methods, you can overload constructors by arity.
## Operators
Operators are just special syntax for regular [method calls](method-calls.html) on the left hand operand (or only operand in the case of unary operators like `!` and `~`). You can define them like so:
:::dart
class Unicorn {
// Infix:
+(other) {
IO.print("Adding to a unicorn?")
}
// Prefix:
! {
IO.print("Negating a unicorn?!")
}
}
This can be used to define any of these operators:
:::dart
// Infix:
+ - * / % < > <= >= == != & |
// Prefix:
! ~ -
Note that `-` can be both a prefix and infix operator. If there's a parameter list, it's the infix one, otherwise, it's prefix. Since Wren supports overloading by arity, it's no problem for a class to define both.
Operator overloading is really useful for types like vectors and complex numbers where the reader knows what the operators will do, but can make code deeply confusing if overused. When in doubt, use a real name.
## Setters
[Assignment](variables.html) *cannot* be overloaded. It isn't an operator, and its semantics are built right into the language.
**TODO: ...**
## Fields
**TODO**

View File

@ -159,7 +159,7 @@ pre {
font: 15px $body;
font-weight: 400;
list-style-type: none;
margin: 0 0 6px 0;
margin: 0 0 4px 0;
}
}

View File

@ -50,6 +50,30 @@ Everywhere else, a newline is treated just like a `;`. Note that this is a very
different system from how JavaScript handles semicolons. If you've been burned
there, don't worry, you should be fine here.
## Blocks
Wren uses curly braces to define *blocks*. Things like [control flow](branching.html) allow block bodies. [Method](method-calls.html) and [function](functions.html) bodies are also blocks. For example:
:::dart
if (happy && knowIt) {
hands.clap
} else IO.print("sad")
Here we have a block for the then case, and just a single expression for the else. Blocks have two similar but not identical forms. If a there is a newline after the opening `{`, then the body contains a series of statements:
{
IO.print("one")
IO.print("two")
IO.print("three")
}
If there is no newline, the block may only contain a single expression:
{ "this is fine" }
{ while (this) "is an error" }
These are useful when defining method and function bodies. A normal block body implicitly returns `null`. If you want your method or function to return something different, you need an explicit `return` statement. However, a single-expression block with no newline after the `{` implicitly returns the result of that expression. This is a nice convenience for short methods and functions that just evaluate and return an expression.
## Names
Identifiers are similar to other programming languages. They start with a letter or underscore and may contain letters, digits, and underscores. Case is sensitive.

View File

@ -14,6 +14,7 @@ class Foo {
|(other) { "infix | " + other }
! { "prefix !" }
~ { "prefix ~" }
- { "prefix -" }
}
@ -32,4 +33,5 @@ IO.print(foo != "a") // expect: infix != a
IO.print(foo & "a") // expect: infix & a
IO.print(foo | "a") // expect: infix | a
IO.print(!foo) // expect: prefix !
IO.print(~foo) // expect: prefix ~
IO.print(-foo) // expect: prefix -