My favorites | Sign in
Project Logo
                
Search
for
Updated Feb 24, 2009 by justin.s...@gmail.com
Labels: Featured
Overview  

Brat is a toy language. A little one. Everything in Brat is either an object or a function (or a method, we don't judge.) Sometimes what something actually is is a little hard to determine, but basically things work how you would expect, even if really they are doing something odd.

For example, consider this code:

a.number = 1

This looks like it is creating a field called 'number' on an object called 'a' and assigning the integer '1' to it. However, in reality, it is first creating a number object and then putting it inside a function, which gets assigned to the field 'number'. So that when you do:

a.number

It actually calls the 'number' function in 'a', which returns the number object.

Variables

Variables spring into existence as you need them. Just assign something to them and *poof*, they will be there. Variables have no types. They are very care-free that way and enjoy running through open fields and hugging sequoia.

Names of variables need to start with a letter (upper or lower case), but other than that you can use any mixture of letters, numbers, and many symbols. But, just so you know, everything in Brat tends to be lower case, because no one is more important than anyone else.

Objects

As was said above, most things in Brat are objects. In fact, a whole Brat program is actually a function defined on an object, which then gets invoked. Whee!

There are no classes in Brat, because Brat doesn't need them. It takes a prototyping approach instead. There are two ways to create new objects: either by creating a 'subclass' of an object (the new object will lookup methods in the old one) or by cloning an object (the new object will have the same superclass as the old one.)

You can think of the difference between new and clone as being extending the class hierarchy vertically or horizontally, respectively.

Objects can have fields (or slots or instance variables or whatever you would like to call them). These also are created as you need them.

The example illustrates defining fields and the difference between new and clone:

a = new   # a is now a subclass of the base object
b = a.new   # b is a subclass of a
a.hello = { p "Hello!" }
b.hello  # b can reference methods in its superclasses

c = b.clone  # methods from b (none) copied but still uses a as superclass
b.hello = { p "I'm not c!"}
c.hello   #this calls a.hello still

Functions

Functions are the only things in Brat which are not objects. Functions take arguments and always return the last value in their body. Functions are also closures, they will take a snapshot of the environment when they are created. Functions do not have names. Names are for variables. By the way, functions are the only way to delay execution of code.

Functions look like this:

{ p "this method has no arguments"}
{ arg1, arg2, arg3 | p "this method has three!"}

Functions cannot be called directly, they have to be assigned to a variable first. You can give a function its arguments by using a comma separated list. This might need to be within parentheses. If you do put them in parentheses, make sure they are snuggled up tight to the variable, or else they won't know they go together. They are shy that way.

a = { x, y, z | p x, y, z}
a 1, 2, 3

By the way, you can also chain method calls. Did you know object fields are actually functions, too? Are they functions or methods? Actually, are they really objects, or is everything actually a function? Or is it the other way around??

a = new
a.b = new
a.b.c = new
a.b.c.d = { x | x}
p a.b.c.d(a).b.c.d "hi" # parentheses required in the middle there

Functions can span multiple lines. So can argument lists, if you want.

Binary Operators

Binary operators are basically just special functions that take a single argument. Operators can only contain a mixture of these symbols: ! > < ? - * + ^ ~ @ $ % | & = / \

Operators can be defined like any other function:

a = new
a.? = { x | p "What ", x, "?"}

They can also be invoked like regular functions:

a.? "is up"

But they can also (and more usefully) be used as binary operators:

a ? "is up"

Important note: ALL operators are treated equally (except '=', which is part of the syntax and not an operator) and evaluated left to right. This means there is no such thing as operator precedence, because how would I know what precedence '@' should have for you? However, this means that normal mathematical operators are also evaluated left to right and My Dear Aunt Sally is, sadly, left out in the cold.

Example:

p 1 + 3 * 4  # 16, not 12

Unary Operators

Unary operators are like binary operators, except they take no arguments and need to be cuddled up to an expression. Otherwise, they are pretty much the same. Still working on limiting their rightward reach, however.

Example:

string.! = { my + "!" }

p !"hi"

Associativity

Operators are left-associative, while functions are right-associative (I think). Mix and match for optimal enjoyment!


Sign in to add a comment
Hosted by Google Code