Write a bunch of docs.

This commit is contained in:
Bob Nystrom
2013-12-28 09:37:41 -08:00
parent afdcafcecb
commit 667d393fbb
6 changed files with 257 additions and 16 deletions

View File

@ -1,4 +1,6 @@
^title Flow Control
^title Branching
*Flow control* is used to determine which chunks of code are executed and how many times. Expressions and statements for deciding whether or not to execute some code are called *branching* and are covered here. To execute something more than once, you'll want [*looping*](looping.html).
## Truthiness
@ -55,11 +57,3 @@ An `||` ("logical or") expression is reversed. If the left-hand argument is trut
:::wren
io.write(false || 1) // 1
io.write(1 || 2) // 1
## While statements
**TODO**
## For statements
**TODO**

View File

@ -3,6 +3,8 @@
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.
Classes contain both *behavior* and *state*. Behavior is defined in *methods* which are stored in the class. State is defined in *fields*, whose values are stored in each instance.
## Defining a class
Classes are created using the `class` keyword, unsurprisingly:
@ -12,7 +14,57 @@ Classes are created using the `class` keyword, unsurprisingly:
This creates a class named `Unicorn` with no methods or fields.
**TODO: methods**
## Defining methods
To make our unicorn do stuff, we need to give it methods.
:::wren
class Unicorn {
prance {
IO.write("The unicorn prances in a fancy manner!")
}
}
This defines a `prance` method that takes no arguments. To support parameters, add a parenthesized parameter list after the method's name:
:::wren
// Inside class...
prance(where, when) {
IO.write("The unicorn prances in " + where + " at " + when)
}
Unlike most other dynamically-typed languages, in Wren you can have multiple methods in a class with the same name, as long as they take a different number of parameters. In other words, you can overload by arity. So this class is fine:
:::wren
class Unicorn {
prance {
IO.write("The unicorn prances in a fancy manner!")
}
prance(where) {
IO.write("The unicorn prances in " + where)
}
prance(where, when) {
IO.write("The unicorn prances in " + where + " at " + when)
}
}
When you [call](method-calls.html) the `prance` method, it will select the right one based on how many arguments you pass it.
**TODO: Defining operators and setters.**
## Constructors
**TODO**
## Fields
**TODO**
## Metaclasses and static members
**TODO**
## Inheritance
@ -25,4 +77,10 @@ By default, any new class inherits from `Object`, which is the superclass from w
This declares a new class `Pegasus` that inherits from `Unicorn`.
**TODO metaclasses, supercalls, fields, etc.**
The metaclass hierarchy parallels the regular class hierarchy. So, if `Pegasus` inherits from `Unicorn`, `Pegasus`'s metaclass will inherit from `Unicorn`'s metaclass. In more prosaic terms, this means that static methods are inherited and can be overridden. This includes constructors.
If you *don't* want your subclass to support some static method that it's superclass has, the simplest solution is to override it and make your method error out.
## Superclass method calls
**TODO**

89
doc/site/looping.markdown Normal file
View File

@ -0,0 +1,89 @@
^title Looping
It's hard to write a useful program without executing some chunk of code repeatedly. To do that in Wren, you use looping statements. There are two in Wren, and they should be familiar if you've used other imperative languages.
## While statements
A `while` statement executes a chunk of code as long as a condition continues to hold. For example:
:::wren
var n = 27
while (n != 1) {
if (n % 2 == 0) {
n = n / 2
} else {
n = 3 * n + 1
}
}
This evaluates the expression `n != 1`. If it is [truthy](flow-control.html), then it executes the body: `n = 3 * n + 1`. After that, it loops back to the top, and evaluates the condition again. It keeps doing this as long as the condition is evaluates to something truthy.
The condition for a while loop can be any expression, and must be surrounded by parentheses. The body of the loop is usually a curly block but can also be a single statement:
:::wren
var n = 27
while (n != 1) if (n % 2 == 0) n = n / 2 else n = 3 * n + 1
## For statements
While statements are useful when you want to loop indefinitely or according to some complex condition. But in most cases, you're looping through a [list](lists.html) or some other "sequence" object, or you're terating through a range of numbers. That's what `for` is for. It looks like this:
for (beatle in ["george", "john", "paul", "ringo"]) {
IO.write(beatle)
}
A `for` loop has three components:
1. A *variable name* to bind. In the example, that's `beatle`. Wren will create a new variable with that name whose scope is the body of the loop.
2. A *sequence expression*. This determines what you're looping over. It gets evaluated *once* before the body of the loop. In this case, it's a list literal, but it can be any expression.
3. A *body*. This is a curly block or a single statement. It gets executed once for each iteration of the loop.
### The iterator protocol
It's important to be able to use looping constructs over user-defined sequence-like objects and not just built-in lists. To make that happen, the semantics of a `for` are defined in terms of an "iterator protocol". The loop itself doesn't know anything about lists or numbers, it just knows how to call two particular methods on the object that resulted from evaluating the sequence expression.
It works like this. First Wren evaluates the sequence expression and stores it in a hidden variable. In our example, it will just be the list object. It also creates a hidden "iterator" variable an initializes it to `null`.
At the beginning of each iteration, it calls `iterate()` on the sequence, and passes in the iterator. So in the first iteration, it always passes in `null`. The sequence's job is to take that iterator and advance it to the next element in the sequence (or, in the case where it's `null`, to advance it to the *first* element). It then returns either the new iterator, or `false` to indicate that there are no more elements.
If `false` is returned, Wren exits out of the loop and we're done. If anything else is returned, that means that we have advanced to a new valid element. To get that, Wren then calls `iteratorValue()` on the sequence and passes in that iterator value that it just got from the sequence. The sequence uses that to look up and return the appropriate element.
In other words, from Wren's perspective, the above loop looks something like this:
{
var iter_
var seq_ = ["george", "john", "paul", "ringo"]
while (iter_ = seq_.iterate(iter_)) {
var beatle = seq_.iteratorValue(iter_)
IO.write(beatle)
}
}
The built-in list type implements `iterate()` and `iteratorValue()` to walk over the list elements. You can implement the same methods in your classes to make your own types iterable.
### Numeric ranges
That just leaves iterating over numbers. Often you want to do something a fixed number of times, or with one of each of a range of consecutive numbers. In Wren, that looks like this:
for (i in 1..100) {
IO.write(i)
}
This looks like some special range support in the `for` statement, but it's actually just the iterator protocol all over again. The `..` is a "range" operator. Like all other operators in Wren, it's just syntax for a method call. In this case, we're calling `..` on `1` and passing in `100`. The above example could just as well be written:
var nums = 1..100
for (i in nums) IO.write(i)
The number class implements the `..` method and returns a `Range` object. This is just a simple data structure that tracks a minimum and maximum (here `1` and `100`). The range class implements `iterate()` and `iteratorValue()` to generate a series of consecutive numbers.
If you don't want to execute the body of the loop for the last value, you can use `...` instead to get a half-open interval:
for (i in 1...100) {
IO.write(i)
}
This will print up to `99`, but not `100`.
## Break statements

View File

@ -64,11 +64,14 @@ Wren has a few prefix operators:
They are just method calls on the operand without any other arguments. An
expression like `!possible` just means "call the `!` method on `possible`".
These operators are infix (they have operands on either side):
We have a few other operators to play with. The remaining ones are
infix—they have operators on either side. In order of increasing
precedence, they are:
:::wren
== !=
< > <= >=
.. ...
| &
+ -
* / %
@ -78,6 +81,10 @@ left operand is the receiver, and the right operand gets passed to it. So
`a + b` is semantically interpreted as "invoke the `+` method on `a`, passing
it `b`".
Most of these are probably familiar already. The `..` and `...` operators are
"range" operators. The number type implements those and returns a range object,
which can in turn be iterated over using a [`for`](loops.html) loop.
## Subscript operators
Most languages use square brackets (`[]`) for working with collection-like

92
doc/site/qa.markdown Normal file
View File

@ -0,0 +1,92 @@
^title Q & A
## Why did you create Wren?
Most creative endeavors aren't immediately met with existential crises, but for some reason many programmers don't seem to like the idea of new languages. My reason for creating Wren is pretty simple: I really enjoy building things.
I find it deeply soothing to write a bit of code, see a new test pass and check it in. I seem to be wired to seek concrete accomplishment. I'm not very good at relaxing and doing nothing. I need to feel like I earned a gold star, or a few XP, or levelled up, or something. Too many years as a teacher's pet has left it's mark on me.
## Why did you create *Wren?*
I guess that's not the question you were asking. You want to know why I created *Wren* as opposed to some other language?
* I already know C and it's fun to code in. When I code in my free time, I have limited patience for learning new things. I want to *make*, not *learn-how-to-make*.
* Dynamically-typed languages are a lot simpler to design and build. I like static types, but good type systems are *hard*. Implementing a type-checker isn't too hard, but doing things like stack maps for GC didn't seem like fun to me.
* Creating a scripting language for embedding means I don't have to make a huge standard library before the langauge is useful. Creating a new language is a ton of work. You have to design it, document it, implement it, optimize it. On top of that, you need a standard library, packages, tooling, a while ecosystem. Doing a scripting language cuts that problem down to a much more manageable size while still yielding a language that real people can use for real things.
* I really like classes and objects. I could go into this at length, but I'll spare you.
## Why should *I* care that you created Wren?
Ah, here's the real question. You want to know why Wren might be relevant to you. Good question! Here's the niche I'm trying to fill:
There are a handful of scripting languages that are in use for embedding in applications. Lua is the big one. There's also Guile, increasingly JavaScript, and some applications embed Python. I'm an ex-game developer, so when I think "scripting", I tend to think "game scripting".
Lua is a good answer there: it's small, simple, and fast. But, and I don't mean this as a criticism, it's also weird if you're used to languages like C++ and Java. The syntax is clean but different. The semantics, especially the object model are unusual. Anyone can get used to 1-based indexing, but things like metatables really show that objects were bolted onto Lua after the fact.
I feel like there's an opportunity for a language that's as small, simple, and fast as Lua, but also one that feels familiar and natural to someone with a convention OOP background. Wren is my attempt at that.
Here's an example of doing object-oriented programming in Lua:
:::lua
Account = {}
Account.__index = Account
function Account.create(balance)
local acnt = {} -- our new object
setmetatable(acnt,Account) -- make Account handle lookup
acnt.balance = balance -- initialize our object
return acnt
end
function Account:withdraw(amount)
self.balance = self.balance - amount
end
-- create and use an Account
acc = Account.create(1000)
acc:withdraw(100)
Here's the same example in Wren:
:::wren
class Account {
new(balance) { _balance = balance }
withdraw(amount) { _balance = _balance - amount }
}
// create and use an Account
var acc = new Account(100)
acc.withdraw(100)
I also feel there's room for a language with a minimal, beautiful *implementation*. Lua's code is clean, but not well documented or easy to read. With Wren, I'm trying to make the code as approachable as possible so that others feel confident using it and extending it.
## Why compile to bytecode?
Interpreters come in three flavors, in order of increasing performance: "tree-walk" or line-based interpreters run the code directly from the source or a parse tree. Bytecode interpreters compile the parsed source code to a set of instructions for a virtual machine which they then implement. JIT compilers do something similar but actually compile to the host machine's native instruction set.
JIT compilers are nice, but:
* They are *much* more complex to implement and debug.
* Since they use the machine's native stack, cooperative multitasking (fibers) have to do lower-level shenanigans.
* Many devices like iPhones and game consoles do not allow runtime generated code to be executed.
Bytecode, meanwhile is quite simple while also fast enough for real-world usage. It also makes supporting fibers straightforward since the virtual machine defines its own stack(s) and can switch between them easily.
## What about your other languages?
This is a strange question if you don't happen to know who I am. In the past, I've hacked on a blogged about a couple of other hobby languages. The two most frequent are [Finch](http://finch.stuffwithstuff.com/) and [Magpie](http://magpie-lang.org/). Why a third?
Well, actually, Wren isn't my *third*, it's probably closer to tenth at this point. I try out lots of different ideas. Wren grew directly out of Finch. I started Finch to learn more about implementing an interpreter and also about the prototype paradigm. I learned a ton about both.
What I learned in particular is that C++ is nice but not that necessary if your codebase is relatively small. And I learned that I really prefer classes over prototypes. I started retrofitting classes into Finch but eventually realized it was too big of a change to do through evolution, and thus Wren was born.
Wren is effectively a replacement for Finch to me. I gave it a new name mainly so that I can keep Finch around in case other people want to take it and do something with it. I don't have any intention to work on Finch anymore. Wren scratches that same itch 10x.
Magpie is a trickier one. I really really like the ideas behind Magpie. It's the general-purpose language I wish I had most of the time. I love patterns and multiple-dispatch. I like how it integrates the event-based IO of libuv with the simplicity of fibers.
But it's also a much more challenging project. As a general-purpose language, there's a ton of library work to do before Magpie is useful for anything. It has some unresolved GC issues. And I'm frankly not skilled enough right now to implement multiple dispatch efficiently. Meanwhile, since I started working on Magpie, [Julia](http://julialang.org/) has appeared and [Dylan](http://opendylan.org/) has reappeared. I was really astonished at how much Magpie had in common with Julia when it came out. I created Magpie partially to carry the torch of multiple dispatch, but others are starting to spread that light now.
I think I have a greater chance of success with Wren, but that doesn't mean I don't still love Magpie and want to work on it. I tend to rotate through projects. I rarely abandon them forever, I just take long breaks. Ask me about my roguelike sometime.

View File

@ -27,13 +27,14 @@
<li><a href="syntax.html">Syntax</a></li>
<li><a href="method-calls.html">Method calls</a></li>
<li><a href="variables.html">Variables</a></li>
<li><a href="flow-control.html">Flow control</a></li>
<li><a href="branching.html">Branching</a></li>
<li><a href="looping.html">Looping</a></li>
</ul>
<h2>Types</h2>
<ul>
<li><a href="values.html">Values</a></li>
<li>Classes</li>
<li>Functions</li>
<li><a href="classes.html">Classes</a></li>
<li><a href="functions.html">Functions</a></li>
<li>Fibers</li>
<li>Lists</li>
<li>Maps</li>
@ -45,7 +46,7 @@
</ul>
<h2>Other</h2>
<ul>
<li><a href="faq.html">FAQ</a></li>
<li><a href="qa.html">Q &amp; A</a></li>
<li><a href="performance.html">Performance</a></li>
</ul>
</div>