MoonScript: Dynamic scripting language that compiles into Lua
moonscript.org
moonscript.org
The current MoonScript is in a really tight spot: the aging codebase doesn't get updated, there's no one leading the development, and the community has like 20 members tops. We need people! For both developing the language, discussing its design, and testing the changes. Feel free to drop by and say hi on Discord: https://discord.gg/Y75ZXrD
Also, there's another effort aiming to modernize MS: a compiler written in C++: https://github.com/pigpigyyy/MoonPlus/ - it's new, but it already implements all of the MoonScript language - definitely worth taking a look at.
[1] It started when I tried to add some FP conveniences to MS: https://github.com/leafo/moonscript/issues/407
[2] https://github.com/piotrklibert/AwesomeScript - nothing interesting yet, just a few ideas in the issues
For others, the discord linked above is the official one, so feel free to stop by.
I'm the creator of MoonScript. I code in MoonScript daily, it's an integral part of many of my projects, including the company I run. It's something I launched a very long time ago, it's been featured on HN quite a few times now!
I feel a little bad for threads like this: if you look at the github or the website, it hasn't seen any significant updates in quite some time. The reality is, though, it's reached a level of stability where I don't need to worry about it and I can work on using it to build other things. Although I have many ideas to fundamentally change it, introduce new operators, paradigms, etc., at the end of the day I value more that is has stayed pretty consistent. I have 100s of thousands of lines of MoonScript running in production environments. I'm more interested in refining the tooling & squashing bugs. I'm considering just bumping the version to 1.0 so people don't get confused about the viability of using it. If it's something you think fits your needs then go for it. I will continue to support it indefinitely because of how integrated it is into many of my projects.
Tell me if you have any questions, thanks!
Do you have some place where you organise your thoughts and make plans for Moonscripts' future?
Some things I would like to eventually finish though:
* JavaScript output backend https://github.com/leafo/moonscript-javascript-compiler
* Replacing the AST transfomer with something written in tableshape: https://github.com/leafo/tableshape
* Experimenting with writing an lpeg alternative that works more like a parser generator, experimented here https://github.com/leafo/moonparse
* Formalizing the syntax transformation pipeline (this would be how things like macros could be implemented)
If you have ideas feel free to open issues on the github. I may not be able to reply immediately but at least they are written down somewhere. Thanks
I found Lua to be so bare-bones and even quirky that I yearned for the expressiveness of C. I was so unimpressed and miserable working with it that I wondered if these people in the wild who supposedly love Lua have used another programming language in the past 15 years.
So, with that said, MoonScript looks essential.
that's a design feature. Though I do hate the 1-based indexing...
Edit: 1-based indexing I can live with. The fact that the things you create with {a, b, c} act for the most part like arrays except for the fact that if they contain nils, the "length" operator is undefined and usually stops at the first nil, is what makes Lua unusable for me.
There are many libraries of common utilities that make working with tables-as-arrays more convenient. If you don't want to use them, it's mostly trivial to write them yourself. What you shouldn't do, though, is trying to use the raw tables as arrays: that could indeed be a frustrating experience.
http://lua-users.org/lists/lua-l/2016-09/msg00234.html
Lua has many lengths. From string lengths to table lengths, from number lengths to sequence lengths, from sequence lengths to proper sequence lengths. They are the many lengths of Lua.
The # operator returns string lengths and table lengths. It is the standard length operator, and it's what you usually use to get the length of an object.
The string.len() function returns string lengths. It typechecks the argument to make sure it's a string, but otherwise returns the same value as #.
There are various types of table length. Some of them are sequences, some of them are not. Some have nothing to do with length, but rather with count.
The simplest length is the one provided by ipairs(). It only iterates the "proper sequence" part of a table. That is, it iterates the set of contiguous positive integer keys of a table.[1] When in doubt, this is the length you should rely on. Don't do `for i=1,#t`, but instead use `for i,v in ipairs(t)`.
Another simple length is the one provided by pairs(). This is actually a count. If for every iteration of pairs() you increment a counter, you'll end up with the number of keys in a table. It is rarely used, but can be useful sometimes.
If you want a manual table length, the simplest way to do it is probably to just use an `n` field. While Lua supports this usage, the standard library doesn't, so you have to deal with it manually. While the standard library doesn't natively support the `n` field, some functions, such as table.pack(), may emit it.
Another length option is the highest key of a table. You can get this length by combining pairs() and m ath.max(). It can be useful in some niche applications but it's quite slow, so consider a manual length (see previous paragraph) instead.
By combining pairs() with type(), you can get the number of non-integer keys in a table. While this count does exist, I have never seen it used in practice.
The length operator, #, can also be applied to tables. If your table has a positive integer key, and there's a smaller possitive integer that is not a key (i.e. the value associated with it is `nil`), then this shouldn't be used. When using a table without manual length, this operator is usually faster than any other method[2], but it does have the aforementioned drawback. This table length is the only table length that is unspecified for some tables.
Finally, you can also use your own length algorithm. Use this if you want fast runtime, but the drawbacks of the length operator make it unsuitable for your use-case.
And these are the many lengths of Lua!
[1] - I'm not sure how many people know this, but this property (stopping on first `nil`) is actually described in the manual. That is, ipairs() on a table with "holes" is actually well-defined.
[2] - The Lua manual doesn't guarantee O(log n) time complexity for the length operator. If you want guaranteed O(log n) runtime, use your own length algorithm. This means # could have O(n) time complexity (i.e. equivalent to ipairs()), or even O(m) where m = the number of keys in the table (i.e. equivalent to pairs() + math.max()).
PS: Sorry for the wall of text.
In the future, it'd be best to just drop a link with a short message as to why the link is relevant.
The base language is very simple, but you usually have the building blocks necessary to add the behavior you're missing.
--- get all packed entries, until gap
-- func on the provided list
-- @param list table to be inspected
-- @param func do func what you func want
table.each = function(list, func)
for i,v in ipairs(list) do
func(v, i)
end
end
--- get all entries, packed or not, until completion
-- func on the provided list, completely
-- @param list table to be inspected
-- @param func do func what you func want
table.all = function(list, func)
if (list ~= nil) then
for i,v in pairs(list) do
func(v, i)
end
end
end #{[0]=1,2,3} == #{2,3} -- true
To be able to use zero-based indices ergonomically, the standard library and so one need adjusting as well.Despite how it may appear, 1-based indexing is quite fundamental to Lua.
Additionally, the lua ecosystem is already fractured (luajit is 5.1 + some selective ports of 5.2 stuff) and my feeling is that making this fracture complete will probably work out better in the longer run.
Do you find that your Go code is, if not more complex, at least more verbose than in Scala?
Do you find it to be the case generally, that larger / more complex languages result in code that's easier to read and write? If so, are there many exceptions?
Of course, with larger languages you can also come up with weird examples and say “what do you think this does?” in a brain teaser sort of way, or play “spot the undefined behavior” in C++.
Exceptions? I guess if features are both hard to understand and mandatory, like monads in Haskell or structural typing in TypeScript (not saying they are bad features, just that they add to the cognitive overhead for me). Or if there are lots of features and they’re not orthogonal to each other, leading to lots of surprises. Or certainly if you’re working with people that are overly clever and you find it hard to understand their code.
But the entire language fits in your head, and it's a powerful and composable system. I use LuaJIT fwiw; after you get a taste of its FFI, it spoils you.
First-class environments, overriding of indexing and assignment, coroutines, there's a lot to love (not you, Wirth indexing and default globals).
After that, just build some abstractions. It's very easy to build DSLs in Lua, or if that's a little too dynamic for you (it is for me), it's very easy to use patterns like Builder or use an OO library and build some class taxonomies.
Anyway, Lua's not batteries included in lots of ways. It does take a little time to build it up for your specific usage. But most users think that's a core feature.
My gripes with the language are probably common: no arithmetic-assignment operators like "+=", no real arrays, few array-like operations built-in, array-like tables' first index is 1, no integer type...
Maybe some of your frustrations come from the characteristics of the PICO-8 API and its development environment. It leans on you to implement a lot of basic game logic in a single file, and if you're editing within PICO-8, you only have a basic text editor with a 128x128 pixel looking glass view into that file. I find that Lua works best when you offload a lot of the gritty logic to the host application and use Lua mostly as a glue language, but in PICO-8 the opposite mostly seems to work to its advantage because it's more approachable to newbies with its small, obvious API surface and all-in-one development environment.
LuaJIT is still one of the fastest VMs around and it's worthwhile to be used as a backend either by transpiling to Lua or compiling directly to LuaJIT bytecode. Here is a project which implemented both approaches: https://github.com/rochus-keller/Oberon
And I read a lot of their academic papers which taught me a lot about PL design and implementation.
However whenever I try to program in Lua it feels both impoverished and verbose compared to Python. People complain about runtime errors in Python but Lua has even more of them. And the libraries are significantly worse for the same task.
The language itself being bare bones is great. The standard library being bare bones is not so great.
I do not blame them though- the language has gone through several 2.7 ~ 3.0 years of the snake shisms.
PS: Looked around, and it turns out - there is even a lua implementation for the javascript vm..
It's not that JS is awful in itself, it's more that the combination of HTML, JS and CSS is not optimal for creating applications, especially when compared with some desktop options.
If you want to understand the Lua love, check out some of the other game frameworks like Cocos2D, MOAI, or Godot ..
I've used pretty much every language under the sun, but I keep coming back to Lua as my first choice for scripting because its so efficient, and easy to use. There really isn't much that can't be done with Lua and metatables. I prefer it over python because python dependencies are hell, whereas luarocks is a dream by comparison .. plus, libffi is just so darned useful ..
2012 https://news.ycombinator.com/item?id=4741331
2011 https://news.ycombinator.com/item?id=2871748
A bit more from 2011: https://news.ycombinator.com/item?id=3342912
Threads about the related web framework:
2019 https://news.ycombinator.com/item?id=19011356
2014 https://news.ycombinator.com/item?id=7744777
2013 Show HN: https://news.ycombinator.com/item?id=5602917
> Fennel is a lisp that compiles to Lua. It aims to be easy to use, expressive, and has almost zero overhead compared to handwritten Lua.
If you want to see a large-ish example of what you can do with moonscript the howl editor³ is a great example. It is also a nice extensible editor in its own right, including a very usable vi mode.
edit: Or - I guess - some other scriptable media player, as being extensible is the thing that matters to me. Unless someone magically matches my quirks with their non-scriptable player ;)
I once came close to trying to create a near-identical fork of the project which changed the backslash to something else, but I figured it'd be pretty pointless. I know I'm definitely not the only one who dislikes it, at least.
You're not. In my fork, I plan to replace `\` with `:` and `:` with `=`, so it's closer to Lua, and less irritating to look at. I need to figure out how to code that while retaining some backward compatibility, but "fixing" this is one of the major goals of my fork.
http://www.onionsoft.net/hsp/v33/doclib/hspprog.htm#EXPRESSI...
I also hate it (along with HSP in general). Anything that exists outside the grain of programming language conventions so baked in as basic arithmetic operators throws me off.
Efficient, expressive, elegant Nim is a statically typed compiled systems programming language. It combines successful concepts from mature languages like Python, Ada and Modula.
C FFI is unsafe, as well as taking an address of something; but you rarely need these things unless you are already interfacing with unsafe C code.
It does not, however, delineate unsafe parts into an unsafe{} scope the way Rust does.
I get that the stdlib is clearly inspired by python¹, and that using a reST-ish subset for documentation is Python-y. Beyond that surface scratch the comparison just falls apart, and often seems to end up as a pointless sticking point when introducing co-workers to nim. You can't even ignore the idea, as the moment they crack the awesome Nim in Action book or the official docs they're immediately shown it.
1. down to being able to just guess module names in a few circumstances.
But nothing at all about it is perlish that I can think of.
Yeah, I could probably have picked a better example or more clearly expressed my thoughts. I was attempting to make a point about concepts such as the uniform function call syntax feeling like a perl-style TWMTOWTDI feature to me.
[The crux was supposed to be about how quickly just seeing the Python comparison in the docs ends up in a rabbit hole discussion. I didn't help with my own poor comparison.]
In that case, there's OOP modules for raw Lua that work well. I'd prefer to stick with Lua.
Some years ago I learned Io - another prototype-based language, similar to Self - and I was amazed at how expressive it is based on a very small set of core primitives. All the primitives, including async calls in coroutines, are either built-in in Lua or are trivially implemented with a small code transformation.
> Yes, the class stuff in MS is plain wrong
There's nothing wrong about it, I'm sorry you don't like it! I'm happy that you have your own ideas but to go around saying it's wrong isn't very cool. The system was very intentionally designed. Now that's it's been 9 years and I've written 100s of thousands of lines of MoonScript, the class has proved to be very reliable. It compiles to simple concepts that are easy to reason about when working with both large and small code bases.
> The thing is, the prototypal, copy-on-write nature of Lua object orientation
This line is confusing to me. There is nothing about lua that is fundamentally copy-on-write. That would have to be a choice the developer makes, but it would be hard to enforce with language primitives unless you're hiding data within meta-tables
I think you're getting hung up on details that have nothing to do with MoonScript: if you want a different language then use a different language. Don't go around saying it's wrong because it's not the language you want.
an OOP module from Lua is likely going to work the same way. Most class based languages would behave the same (Python, Javascript are examples I can think of)
A "class attribute" is a value stored on the object that represents the class. This is a prototypical language, so all instances of a class share the same prototype associated with the class.
Regarding immutability, you could use metatable tricks or a library to enforce immutability on a Lua table. That's not something the language provides.
> to give an instance its own state you gotta define attributes in the constructor
So I believe the reason why you're making this distinction is because the prototypical inheritance and the explicit section that talks about this in the documentation. MoonScript lets you have any value be part of the prototype, not just methods/functions.
So I guess I'm writing all this to say that it's not weird, it's just the nature of prototype-based languages. I specifically call out this case in the docs to help people not get stuck.
Is that so? Or is inline MoonScript code within C files not common?
I recommend doing the MoonScript compile time at program build time to avoid any unnecessary compilation during runtime.
I’ve been thinking about the syntax of an embeddable language myself, and have ruled out significant indentation because of the difficulty of writing such code inline inside C files. If that’s not a common use case, maybe I should reconsider...
This means that MoonScript compiled ahead of time will have the same exact result as running it on the fly.
Types are one of those things that will stick in use. We will also probably see a wild diversity of type systems in experimental languages, as there is very likely one better than everything we use today.
Even if that is true, there are potentially a lot of dimensions to consider in solving the problem of what is better or worse. Some of these dimensions, or where in that dimension what-is-better falls, take a long time to discover and are different for different problem spaces. Sometimes you think you've got it right only to learn that you were wrong much later.
But it isn't true. Fashion is by any indication only loosely concerned with utility and sometimes settles on downright masochistic flavors-of-the-day.
That is a language I wouldnt mind to work with on both server and client.
Nim does server and client as well (compile down to C or JS serverside, JS clientside), and has Python inspired syntax and standard library.
GWT gives you that for Java; Emscripten and recently WASM gives it to you with basically anything gcc can compile and then some.
There is no need to wait.
Does anyone know if I can use the generated Lua in Redis?
It would seem that there is no reason you couldn't.
Isn't nodejs faster
See: https://gist.github.com/spion/3049314 https://en.sfml-dev.org/forums/index.php?topic=18260.15
Overall, the fastest dynamic language JITs are probably V8 and other JavaScript runtimes - it’s worth noting that none of these use LuaJIT-style tracing.
https://github.com/LuaJIT/LuaJIT/issues/37/
That and the quad-color garbage collector would ensure LuaJIT's dominance for many years to come. The quad-color is well described, and someone might successfully implement it at some point; I doubt there's another human alive who could implement hyperblock scheduling. I'd love to be wrong.
Does anyone know what he is currently working on ?