DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

100 Languages Speedrun: Episode 89: MoonScript

MoonScript is CoffeeScript for Lua.

It doesn't seem to be maintained much anymore. The most recent release was back in 2015, and it doesn't work with the latest Lua. You can still run it with non-release version, with luarocks install moonscript --dev.

Hello, World!

Hello World is as simple as it gets. Newline is automatically inserted:

#!/usr/bin/env moon

print "Hello, World!"
Enter fullscreen mode Exit fullscreen mode
$  ./hello.moon
Hello, World!
Enter fullscreen mode Exit fullscreen mode

FizzBuzz

MoonScript uses indentation base syntax. For loops use Lua syntax instead of .. ranges.

#!/usr/bin/env moon

for i = 1, 100
  if i % 15 == 0
    print "FizzBuzz"
  elseif i % 5 == 0
    print "Buzz"
  elseif i % 3 == 0
    print "Fizz"
  else
    print i
Enter fullscreen mode Exit fullscreen mode

Fibonacci

MoonScript has nice syntax for defining functions with two kinds of arrows, and implicit return. There's also beautiful string interpolation.

#!/usr/bin/env moon

fib = (n) ->
  if n <= 2
    1
  else
    fib(n-1) + fib(n-2)

for n = 1,20
  print "fib(#{n})=#{fib(n)}"
Enter fullscreen mode Exit fullscreen mode

Unicode

Unicode is broken in Lua, and MoonScript does not fix it. Method call syntax is also really weird with a backslash, as . is taken for regular function call (that doesn't pass extra self as first argument).

#!/usr/bin/env moon

print "Hello"\len()
print "Żółw"\len()
print "💩"\len()

print "Żółw"\upper()
print "Żółw"\lower()
Enter fullscreen mode Exit fullscreen mode
$ ./unicode.moon
5
7
4
ŻółW
Żółw
Enter fullscreen mode Exit fullscreen mode

Person class

It's just an empirical fact that people overwhelmingly hate prototype-based inheritance, and want classes. MoonScript provides the same two main things as CoffeeScript - nicer syntax, and class-based OOP.

#!/usr/bin/env moon

class Person
  new: (@name, @surname, @age) =>
  __tostring: =>
    "#{@name} #{@surname}"

maria = Person("Maria", "Ivanova", 25)
print "#{maria} is #{maria.age} years old"
Enter fullscreen mode Exit fullscreen mode
$ ./person.moon
Maria Ivanova is 25 years old
Enter fullscreen mode Exit fullscreen mode

This is fairly nice. There's no default __tostring, it's just table: 0xADDRESS, so we really should provide something. Constructors auto-assign any @arguments, so you don't need to do the boring thing every time. I'm actually a bit disappointed in Ruby for not doing this obvious thing 80% of the time:

class Person
  new: (name, surname, age) =>
    @name = name
    @surname = surname
    @age = age
Enter fullscreen mode Exit fullscreen mode

Vector

We can do enough operator overloading to make vectors work. Which exact operators can be overloaded depends on Lua version (and games often ship with older versions):

#!/usr/bin/env moon

class Vector
  new: (@x, @y) =>
  __tostring: => "<#{@x},#{@y}>"
  __add: (other) => Vector(@x + other.x, @y + other.y)
  __eq: (other) =>
    @__class == other.__class and @x == other.x and @y == other.y

a = Vector(20, 60)
b = Vector(400, 9)
c = a + b

print a
print b
print c
print c == Vector(420, 69)
Enter fullscreen mode Exit fullscreen mode
$ ./vector.moon
<20,60>
<400,9>
<420,69>
true
Enter fullscreen mode Exit fullscreen mode

This doesn't really help with printing plain Lua tables like arrays, just MoonScript classes.

Wordle

Let's do Wordle.

The first problem we run into is that Lua lacks the most basic functions like string.split, string.contains etc. There's one included as import in moonscript.util, but it leaves extra "" at the end, so we need to remove it.

This code looks bad because Lua desperately needs a better standard library, and MoonScript does not come with one:

#!/usr/bin/env moon

import split from require "moonscript.util"

readlines = (path) ->
  file = io.open("wordle-answers-alphabetical.txt")
  text = file\read("*a")
  file\close!
  lines = split text, "\n"
  table.remove(lines) -- remove empty "" at the end
  lines

random_element = (array) ->
  array[math.random(#array)]

class Wordle
  new: =>
    @words = readlines("wordle-answers-alphabetical.txt")
  report: (word, guess) =>
    for i=1,5
      letter = guess\sub(i,i)
      if word\sub(i,i) == letter
        io.write "🟩"
      -- non-regexp string.contains?
      elseif word\find(letter, 1, true)
        io.write "🟨"
      else
        io.write "🟥"
    io.write "\n"
  __call: =>
    word = random_element(@words)
    guess = ""
    while guess != word
      io.write "Guess: "
      guess = io.read!
      if #guess == 5
        @report(word, guess)
      else
        print "Guess must be 5 letters long"

game = Wordle()
game()
Enter fullscreen mode Exit fullscreen mode
$ ./wordle.moon
Guess: audio
🟥🟥🟥🟥🟨
Guess: stone
🟥🟥🟨🟥🟨
Guess: lover
🟨🟩🟨🟩🟥
Guess: vowel
🟩🟩🟩🟩🟩
Enter fullscreen mode Exit fullscreen mode

Should you use MoonScript?

It's unfortunately abandoned, and it's hard to recommend abandoned languages.

Otherwise there's a pretty obvious use case. So many games are coded in Lua, and MoonScript compiles into fairly clean Lua, so if you want to mod Lua-based games like Factorio, maybe MoonScript would be a reasonable idea.

I don't really recommend Lua or MoonScript for anything new, but as a game modder you're stuck with whatever game developers decided to use, so having this an as option is nice.

If anyone feels like giving this project a shot, and release a new working version, maybe it would be of some use for modders.

I feel like it would provide a lot more value if such revived MoonScript also came up with decent standard library comparable with what Ruby, JavaScript, and Python have.

Code

All code examples for the series will be in this repository.

Code for the MoonScript episode is available here.

Top comments (5)

Collapse
 
romeerez profile image
Roman K • Edited

Thank you!

MoonScript was created and mostly used by a single person Leafo. And that's no wonder. Also Leafo is a creator of a web framework Lapis, if we compare it with express.js - no doubt even though Lapis was created and used only by a single guy, it's times more superior! Leafo created MoonScript to make it easier writing web framework, and he created web framework to create a web portal for amateur games itch.io/. Leafo had to create a lot of libraries on this hard way, and he also created moonrocks - luarocks alternative for MoonScript.

That's what Lua ecosystem looks like - small group of people are busy with creating game mods, one legendary person Mike Paul created best in class JIT compiler, and second legend keeps pushing packages for whole decade.

I don't really recommend Lua or MoonScript for anything new, but as a game modder you're stuck with whatever game developers decided to use

What would you suggest instead for embedding? Given that we need fast, lightweight language for simple scripting, with easy to use C or C++ bridge? JS is fast enough for most tasks, but not that lightweight. Lua fits perfectly when need to add a bit of logic into something complex and performant, such as web server, game engine, database, or something with limited resources as IoT. Also Lua is a language of AwesomeWM - lightweight tiling window manager for linux.

JS, JS and JS for everything, I know, Lua has endangered community, tiny ecosystem.

Probably Go, it also aims to be simplistic, surpasses Lua by memory and speed, ecosystem

Collapse
 
taw profile image
Tomasz Wegrzanowski

I don't really know how easy it is to embed different languages, but I can definitely see why JavaScript is winning over Lua on its home turf.

Does it even matter that it's more lightweight? Games are routinely over 100GB these days, what's a few MBs even?

Collapse
 
romeerez profile image
Roman K • Edited

To be honest - for games it doesn't matter, even on cheaper mobile devices few MB won't change the weather. By lightweight I mean for RAM.

I remember talking to a mobile app developer who was very proud of packing quite complex app with nice graphics into 10 MB, around 5 years ago. And now it's absolutely normal if app is written on React Native and eats 300-400 or more MB or RAM, You know, I like Lua probably because of nostalgia, probably it's no longer a competitor, probably for some years already, but it was so nice to play with back in time, before the ES6 reborn.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️ • Edited

It's unfortunately abandoned, and it's hard to recommend abandoned languages.

It's hard to call a language "abandoned" that is being used by its creator in a project as huge as itch.io; as far as I'm aware, it's not being worked on because it is intentionally being kept stable for compatibility reasons.

If you want a more exciting dialect of moonscript with a bunch of new features, yuescript offers exactly that.

I don't really recommend Lua or MoonScript for anything new

I do. It's a great language and even now is ahead of others in some aspects.

Collapse
 
taw profile image
Tomasz Wegrzanowski

Last release was September 25 2015 and it doesn't work witch latest Lua version, so looks pretty abandoned to me. A lot of no-longer-updated stuff still runs somewhere.