MoonScript (and Lua)

Lua is my favorite programming language. That puts me in a very small minority, even among Lua programmers (who seem to prefer C). For me, Lua is the first choice. But the more you use any tool the more you come to realize it has some faults. Lua is no exception. First and foremost is the lack of libraries and tooling. Lua does not come 'batteries-included' like Python or Ruby. It does not come with a package manager. There isn't even a standard linter (luac -p is closest). This is because Lua is an embeddable language, first and foremost. It forgoes the batteries. It expects you, the embedder, to provide them. LuaRocks is the most popular package manager for Lua and is easiest method to provide batteries.

Secondly, Lua is a minimal language. It lacks integers, ++/+= operators, bit operators, classes, continue, switch, the ternary operator, regular expressions and some other things I rarely miss. It is quirky in other areas. Lua has only one data structure: the table (i.e. an optimized associative array). It has no standard class system. But the quirks are workable and, in some cases, advantageous. The most unexpected failure of Lua, however, is an oversight: variables are global by default. Misspell a variable used in an assignment? Congratulations, you've created a new global variable! Lua does, however, possess the most important features: lexical scoping, coroutines, first class functions, closures, tail recursion, an incremental garbage collector and a wickedly fast JIT compiler with an FFI library.

MoonScript is a practically unknown but highly useful language which aims to improve on Lua. MoonScript is to Lua what CoffeeScript is to JavaScript. It compiles a syntax similar to CoffeeScript into valid Lua. MoonScript does solves many of the 'problems' of Lua. It adds continue, switch, +=, function shorthand, a default class system, table comprehensions, slices, destructured assignments, default parameters, and a diabetes-inducing amounts of sugar. Most importantly, variables are local by default. MoonScript is extremely terse, typically reducing the character count by 20-30%. So let's take a brief look at MoonScript (and a bit of Lua).

Ubuntu/Debian
sudo apt-get install lua5.1 luarocks
sudo luarocks install moonscript

Or you can install LuaRocks from GitHub.

sudo apt-get install lua5.1
git clone git://github.com/keplerproject/luarocks.git
cd luarocks
./configure
make
sudo make install
sudo luarocks install moonscript
Windows

Download and install Lua for Windows. This installs Lua 5.1, LuaRocks, and a whole slew of libraries. Then download the MoonScript binary and extract it to somewhere on your path.

Getting Started

Now that we have lua (the interpreter), moonc (the MoonScript compiler), and luarocks (the package manager) installed we can add the batteries. There are a number of libraries that are essential for most uses. Now we can create an interesting first program. We'll create a derivative of the permutation example from Programming in Lua (a good read if you're interested in Lua).

There are two ways to run this program. During development you'll want to use moon start.moon. moon rewrites errors such that the correct line number the error occured on is displayed. For deploying libraries you'll want to use moonc start.moon. This builds a correspondingly named Lua file. moonc attempts to produce legible Lua code, but it uses mangled names. As an example let's look at the Lua output for moonc start.moon.

and the output:

We have 24 permutations:
2,4,6,8
...
8,6,4,2

Yikes. That's not very legible at first glance. The variable names are hideous but decipherable. _accum_0 is the accumulator table. _len_0 is the current index of that table. It should be clear how MoonScript constructs table comprehensions (it's a glorified for loop). But you need to be cautious when using them. MoonScript will generate a table comprehension as an immediately executed function when passed directly to a function (i.e. without being assigned to a variable). This is functionally the same but it can reduce performance. Slices, akin to Python's slices, can be used with comprehensions. Play with the code: switch from odds to evens and add slices.

Classes

Lua doesn't have classes, but it does have objects (tables) and a metatable mechanism which simplifies the creation of a class system. Within the Lua community, the library middleclass is fairly common. Use any Lua class library with MoonScript you so desire. Or refuse to use a class library. Lua is kind enough to give you the option. But before you make any decision let's look at an example of MoonScript's class system.

and the output:



I won't bother showing the Lua code. It's a mess. I find the class system to be conceptually attractive. First, it doesn't inherit metamethods by default. This is a safe choice, but it is the reason for the Object class in the above example. Secondly, the code it produces would draw ire when committed to a pure Lua repository. If you're working on a pure Lua project, don't bother with MoonScript's class system. Use middleclass or the closure-based approach. Personally, the closure approach is ideal. It avoids MoonScript's irregular \ method invocation operator and allows for private variables (as upvalues).

Conclusion

I would cover a few other important features, but the very clear manual renders that a waste. It turns, then, to thoughts. MoonScript offers the sugar that Lua lacks. It's great for writing short scripts or tools. Using MoonScript, I see myself breaking scripts into multiple, smaller files. This allows easy verification as the Lua fits within one or two pages. The average function size decreases and I see myself favoring short one or two line functions. MoonScript's concise syntax allows for maximum brevity, without often compromising clarity.

Unfortunately, much like Lua, it has a number of problems and issues to overcome. MoonScript has an almost non-existent community. The error messages from the compiler are the uniformly uninformative: 'Failed to parse'. Whitespace is significant, much like Python and CoffeeScript. If you're not accustomed to significant whitespace, prepare for surprises. If you're writing a large program in MoonScript, be sure to verify the Lua output from time to time. Compiling can be a chore, but luckily moonc -w $PWD watches your directory for changes and compiles immediately.

In the end, I can't help but like MoonScript. In spite of its faults, it manages to increase productivity and decrease eyesore. I've added it to my toolbox, alongside Lua. If you also find MoonScript interesting and would like to build something cool, check out Lapis (a web framework) and/or LÖVE (a Lua game engine).