An Overview of MoonScript

MoonScript is a language that compiles to Lua inspired by CoffeeScript. The MoonScript reference manual is a great place to learn exactly how MoonScript works with Lua, but if you don’t know Lua it can be difficult to read.

As an alternative, here is a tutorial and overview of some of MoonScript’s syntax with no Lua knowlege required.

If you've worked with JavaScript (or CoffeeScript) before, you'll feel right at home with the features provided by MoonScript (and Lua).

Hello World

Writing “Hello World” is as simple as calling the print function with some value, like the string "Hello world":

-- I'm a comment!
print "Hello world"

Comments begin with -- and continue to the end of the line.

print is a built in function takes any number of arguments and will print each one separated by a tab character.

You can read more about print on the Lua reference manual. MoonScript is just another way of writing Lua, so all built in Lua functions can be used directly in MoonScript as well.

Variables

Variables come into existence when they are first assigned, and they are overwritten when assigned again:

x = "Hello"
y = 4000
y = 34

If you are creating or assigning multiple variables at once, you can list their names on the left of the = and their values on the right.

a, b, c = 1, 2, 3

Values

The basic types in MoonScript numbers, strings, booleans, functions, tables and nil. Numbers and strings are just as you expect. We can join strings using the concatenation operator, .., and we can get the length using the length operator, #.

x, y = 10, 22
x += (y - 100) / 2

a, b = "hello", "world"
print a .. " " .. world
print "length of a:", #a

The two boolean values are true and false. The not operator is used to negate a boolean value. and and or keywords perform their respective boolean operation.

javascript = true
moonscript = not javascript

fast = true
strong = false

warrior = tall and strong

false and nil are considered falsy and everything else is truthy. For example the result of the expression not "hello world" is false because that is the opposite of a truthy value.

We can compare values with all the standard comparison operators: ==, !=, <, <=, etc. Greater than and less than are only defined for numbers (by default).

The other types are discussed below.

Functions

Functions are first class objects, meaning they are values that are stored in variables just like any other object (like numbers or strings).

Functions are created using the arrow operator. A blank function that takes no arguments and does nothing is simply the arrow ->. You can call a function with no arguments by using the ! suffix operator.

-- here we create, then call a function that does absolutely nothing!
fn = ->
fn!

If the body of the function has only one statement, it can be placed after the arrow on the same line. If a function is made up of multiple statements they can be placed new indented lines following the arrow.

say_hello = -> print "Hello there"

say_hello!
say_hello!

say_more = ->
  print "My favorite snack is:"
  print "Ice Cream"

say_more!

Arguments

If a function takes arguments, we can specify a list of argument names wrapped in parentheses before the arrow:

say_name = (name) -> print "Your name is:", name

say_name "MoonScript"

A function may take any number of arguments when called. If there are too many, the extra ones are discarded, if there are too few, the missing arguments get a value of nil.

When calling a function that has arguments, argument values are listed after the function name separated by commas. Parentheses are optional (but required in some cases to avoid ambiguity).

print_sum = (x, y) -> print x + y

-- these two are exactly the same
print_sum 10, 12
print_sum(10, 12)

Notice now that print is just a regular function, and we've been calling it like this all along. In fact, we can give it another name, or remove access to it altogether.

write = print
write "hello"

print = nil
print "hi" -- this is now a runtime error

Returning

Functions in MoonScript implicitly return the last statement. This means that the last statement in the functions body is the return value. You can also explicitly return by using the return keyword.

-- these two do the same thing:
add_1 = (x, y) -> x + y
add_2 = (x, y) -> return x + y

If MoonScript can’t figure out how to get a return value from the last statement, nil is returned. Note that assigning a variable does not have a return value, so an assignment at the end of a function body will cause the function to return nil.

Default Argument Values

Function arguments can have default values. Just assign the argument name a value in the argument list using =.

add = (x, y, is_verbose=true) ->
  print "adding x and y" if is_verbose
  x + y

The default value is used whenever nil is passed to that argument, which happens when fewer number of values than arguments are passed into the function.

Multiple Return Values

A function may return multiple values. Just separate them by commas:

double_both = (a, b) -> a * 2, b * 2

x, y = double_both 10, 20

If you are calling a function and it’s last argument is another function call that returns multiple values then all of those return values are passed as arguments.

If the function with multiple return values is not called in the last argument position then only the first value returned is kept and the rest are discarded.

some_numbers = -> 1,2,3

print some_numbers! -- will print 1    2    3

print some_numbers!, "hello" -- only prints 1,    "hello"

Variable Number of Arguments

If your function takes multiple arguments, then we can join them all into a special argument name called .... It must be at the end of the argument name list in a function declaration.

We can then reference ... as a value, and it returns all the extra arguments in the same way that a function with multiple return values returned.

Here we create a log function that prints all its arguments, but with the text “LOGGING” in front.

log = (...) ->
  print "LOGGING", ...

log "hello", "world"

We can do some more interesting things by putting ... into table which we will see below.

Tables

Tables are the universal data structure of MoonScript (and Lua). They are a combination of an array and a hash table. We may refer to an instance of a table as an object.

As Arrays

To create a simple array table we just list values separated by commas inside for a pair of curly braces.

We can then access the elements of a table using square brackets.

Notice that array tables are indexed starting at 1 (instead of 0 like you might be familiar with in other languages).

x = { 1, 2, 3, "hello" }

print x[1], x[4]

If we try to print a table, we get something not so useful like table: 0x1c1f630. Luckily, to we have a nifty built in function called unpack that we can use to quickly get all the values in an array table.

unpack returns all the values in an array table as multiple return values:

y = { "unpack", "is", "cool" }
print y -- shows the address of the table in memory
print unpack y -- shows the contents of the table

The length operator, #, can be used to get the size of a table:

y = { true, false, true, true, false }
print #y -- prints 5

Inside of curly braces, we are free to manipulate our whitespace. Commas can optionally be replaced by a newline as well.

identity_matrix = {
  1, 0, 0
  0, 1, 0
  0, 0, 1
}

To remove something from a table, just set its value to nil.

arr = { 5, 6, 2, 4, 5 }
-- remove the last item in the array
arr[#arr] = nil
print #arr -- prints 4

When you try to get a value from an index that doesn’t exist in a table, it will return nil.

As Hash Tables

In addition to numbers, we can index entries in a table on any other value. Including other tables.

moon_script = {
  name: "MoonScript"
  release_year: 2011
  traits: { "dynamic", "interpreted" }
  links: {
    homepage: "http://moonscript.org"
    reference: "http://moonscript.org/reference"
  }
}

Alternatively we can leave off the curly braces, and use indentation. The same structure as above:

moon_script =
  name: "MoonScript"
  release_year: 2011
  traits: { "dynamic", "interpreted" }
  links:
    homepage: "http://moonscript.org"
    reference: "http://moonscript.org/reference"

We can stuff a hash on one line with or without curly braces, just separate the values by commas.

color = red: 255, green: 128, blue: 45

Looking up values who have string keys in the hash can be done using .. Likewise, we use the same syntax to assign to when updating values.

print moon_script.links.homepage
moon_script.name = "MoonScript!"

As mentioned above, we can use any value to index on. We use square brackets to enclose expressions that give use our values to index on.

x = {
  ["name"]: "MoonScript" -- same as `name:`
  [(5 + 10)*2]: true
  [->]: true
}

print x["name"] -- same as `x.name`

print x[->] -- prints nil. We've created two different functions!

If you index on anything other than a string, number, or boolean, then it is index on the address of the object. So although two empty function literals, or two empty tables mean the same thing, they are different objects.

a, b = {}, {}
assert a != b

As Both

Tables are not either a hash or an array, but they are both at the same time. We can combine the syntax to produce interesting results. For example, storing meta-data in an array:

hats = {
  "top hat", "bowler", "wizard"
  last_updated: "January 12th"
}

Later on when we look at iteration, we will see how you can only iterate through the array values so the hash values don’t get in in the way.

Control Structures

Conditionals

Most of these should be pretty familiar. Remember that indentation is used to describe blocks of code.

using_moonscript = true
if using_moonscript
  print "Keep it up!"
else
  print "go to moonscript.org"

-- or on one line
have_coins = false
if have_coins then print "Got coins" else print "No coins"

-- elseif
height = 12
if height < 4
  print "You are short"
elseif height < 6
  print "You are average"
else
  print "You are very tall!"

We can also use the if statement as a value, say as an argument to a function. The last statement of each block of the if statement is used as the returned value.

msg = if using_moonscript
  "yes"
else
  "no"

Another type of syntax lets us decorate any line with in if statement by putting it at the end:

print "Hello!" if greet_user

If a conditional value is false or nil then it will take the failure path. Any other value is seen as true. This includes the number 0 and the empty string.

There is also a switch statement:

print "You should wear:"
switch shirt_color
  when "blue" then print "black slacks"
  when "hawaian"
    if in_hawaii
      print "hula skirt"
    else
      print "brown corduroys"
  else
    print "blue jeans"

Looping

There are three looping constructs, the numeric for, the generic for in and the while loop.

Numeric for let’s us specify a start number, end number, and optionally a step size. The bounds are inclusive.

for i = 1, 10 -- 1, 2, ..., 10
  print i

min, max = 2, 20
for k = min, max, 2 -- even numbers from min to max
  print k

-- print items in array
arr = { "hello", "world" }
for j = 1, #arr
  print arr[j]

Generic for in lets us loop over an iterator. Lua has built in function called ipairs that creates an iterator for an array table:

Iterators can return any number of values which can be named in the for statement. ipairs yields the index and the value for each iteration.

arr = { 5, 6, 8, 6, 32 }
for i, v in ipairs arr
  print v

ipairs only gives us the array components of the table, not any hash components. We can use the pairs function if we want to iterate through both array and hash values.

Because it is so common to loop over just the array values of a table, MoonScript provides a special syntax. This specialized form is also slightly faster because it skips the overhead of using an iterator.

We use the * prefix operator.

for v in *arr
  print v

When using the * operator, we can optionally specify starting and ending indices, and even a step size (just like our numeric for loop). Using a negative index here represents that many places from the last index.

-- iterators over the 2nd to 5th elements
for v in *arr[2,5] do print v

-- from the 2nd to the end
for v in *arr[2,] do print v

-- from the 2nd to the 2nd to last
for v in *arr[4, -1] do print v

-- starting from 1st, every other element
for v in *arr[,,2] do print v

Finally, there is while, which works how you would expect:

remaining = 10
while remaining > 0
  print "remaining:", remaining
  remaining -= 1

List Comprehensions

Often we find ourselves writing short chunks of code to transform a arrays by simple expressions. A list comprehension let’s us write these idioms in a minimal amount of code.

Here is an example makes a new array containing each value doubled from the original.

arr = { 5, 6, 2, 9 }
doubled = [v * 2 for v in *arr]

The for in loop here functions the same as the one described above.

We can also limit the included values using a when clause.

-- return halves of numbers that are evenly divided by 2
numbers = { 7, 4, 3, 66, 3 }
halved = [v / 2 for v in *numbers when v % 2 == 0]

You can have any number of for in and when clauses in a comprehension. Multiple for in clauses are equivalent to nested loops:

a, b = {4, 5, 6}, { 9, 8, 8 }
coords = [{x,y} for x in *a for y in *b]

Table Comprehensions

When working with hash tables, we can use curly braces to write a comprehension that generates both keys and values. Separate the key and value by a comma.

tuples = { {"hello", "world"}, {"hi", "there"} }
tbl = {tup[1], tup[2] for tup in *tuples}

Object Oriented Programming

If we put a function inside of a table then we've created object oriented programming by giving that table a method. We can also store state in the table as well.

object = {
  state: 100
  say_hi: -> print "hello"
}

object.say_hi!

We say a method has a receiving object, which is the object that the method operates on. Unlike other languages, we need to manually pass around the receiving object. Luckily MoonScript gives us syntax for that.

If you've used JavaScript then you're probably aware that the variable named this implicitly carries the receiving object.

We use the backslash \ operator to say “pass the object that this function was called on as the first argument.” Thus, we pass in the receiving object as an argument. It’s customary to name this first argument self.

Backslash is used in place of the final . when accessing and calling a function in a table.

Here’s an example:

counter = {
  count: 0

  increment: (self, amount=1) ->
    self.count += amount

  show: (self) ->
    print "The count is:", self.count
}

counter\increment!
counter\increment 5

counter\show!

There are a few more things MoonScript does to help us with object oriented programming. Because we frequently create functions whose first argument is self, a special function syntax can be used to do this for us.

The syntax is called fat arrow, and looks like this: =>

Additionally, because we frequently access fields in the table named self, we can use the @ shorthand.

@hello is equivalent to self.hello and @fn 1, 2 ,3 is equivalent to self\fn 1, 2, 3.

Here’s the object from above rewritten:

counter = 
  count: 0
  increment: (amount=1) => @count += amount
  show: => print "The count is:", @count

Classes

Now that you've seen object oriented programming in action, you're probably thinking of ways you can create your own functions for creating instances of classes of objects.

In a language as expressive as MoonScript, there are many ways to express something like that, so MoonScript comes with it’s own implementation to save you the trouble of using a library or re-implementing it in all of your projects.

A class is just a template for objects. It says “all objects that have this template should have access to the template’s methods and properties”.

We create a class like so:

class Person
  new: (@name) =>
  greet: => print "Hello my name is", @name

moon = Person "MoonScript"
moon\greet!

There are a couple interesting things going on here.

The body of the class declaration looks just like the hash table syntax. It works the same way.

The class name is called like a function in order to create a new instance. The class name is actually just a regular variable where the class object is placed. It’s value is a special table that can be called like a function.

The special new method is used as the constructor.

In any function, an argument name can be prefixed with@. This causes the value for that argument to be assigned to self with that name. In our example, this sets the name as an instance variable.

If you loop throught the entries in the resulting person object you'll notice it won’t show all of its properties.

for key in pairs person
  print key

Only name will be printed. This is because instances and implemented using metatables. The metatable of the instance governs how properties are looked up in the object. When asked for a property, the table itself is first checked. If it doesn’t have a value stored, then, if a metatable has been assigned to the table it will be checked for a special __index property.

The __index can then be a table itself, and the process continues recursively. This is how inheritance is implemented.

Inheritance

We use inheritance to share implementations of behaviour between similar classes. When a child class extends a parent class, the child class has access to all the properties and methods of the parent class.

In MoonScript the extends keyword is used.

class Chef extends Person
  new: (name, @dish) => super name
  greet: =>
    super!
    print "I like to cook", @dish

super is a special keyword. When called like a function, it calls the function of the same name in the parent class.

In the example above, we redefined the constructor and the greet method so we use super as a convenient way to run the parent’s implementation.

Property Access

In addition to functions, classes can hold any value as well. You have to be careful when declaring tables in the class instead of in the constructor.

class TestClass
  number: 100
  items: {}

a = TestClass!
b = TestClass!

a.number = 1212
a.items[1] = "hello"

print b.number -- prints 100
print unpack b.items -- prints "hello"

The values declared in the class are shared amongst all instances. If the shared value is mutable (like a table), then changes will be visible among all instances.

Values like numbers, strings, and booleans are not mutable. It’s important to notice the distinction between changing the value itself, and changing what is stored in the variable. Storing a new value in an instance variable is safe because it adds or modifies that property in the instance.

When we set a property of the same name on an instance, it shadows the value on the class because properties are looked up first in the instance before looking in the class.

Sometimes we want to share a object amongst all instances, so it’s good to know how it’s done.

Class Objects

Using the class statement creates a new class object and assigns it to the variable that is the name of the class. The class object is a plain old table with a metatable that gives it some extra functionality.

As we've seen, we can create new instances by calling the class object like a function.

We can also access the properties defined for instances by their name.

class SomeClass
  name: "class"
  func: => print "hello"

print SomeClass.name
print SomeClass.func

We can get the declared name of the class with the special __name property, and if it extends anything the parent is accessible from __parent. The __base property is the metatable used by the instances.

There is a distinction between the class object and the __base. The __base holds all the properties available for instances (created in the past or in the future). The class object is an almost empty table. Assigning a new property to the class object will not put it in the base, so it will not be available to the instances. If we want to enhance classes after creation we do it through the __base.

The reason why we can access instance properties through the class object is because its metatable searches the base if nothing could be found in itself.

The class can also be retrieved from any instance using __class:

class Hello
  new: =>
    assert @__class == Hello

Hello!

class World extends Hello
  nil -- a body of nil means this class defines no implementation

World! -- this throws an error, because @__class is equal to World