Lua's great. I recently used it to rewrite a small audio effect framework[1] based on an older project of mine in C[2]. To my astonishment, without any optimization efforts on my part, the LuaJIT version of one effect ran faster than the C version, while another more complicated effect (a filter) only took 2.01x as much time as C. And this was with simple, clean, mostly declarative code (read it on GitHub and see what you think).
One of the goals of this project was to compile effects code to JavaScript with Lua.js[3] and produce a demo that ran in the browser. There, unfortunately, I ran into a showstopper with a Lua.js bug[4] that breaks my approach to creating modules. Unlike LuaJIT and regular Lua, Lua.js is an experimental project and far less mature - though totally awesome. I might make another attempt to fix the problem myself at some point. With a more mature Lua.js, you could write fast Lua code and port it to nearly every environment.
I chose lua because of its built-in coroutines. For a simple mud server, blocking until the next line of input is ready works really well. Because it's not preemptive, you don't have to worry about locking. Because MUDs are so niche these days, you don't have to worry about the userbase scaling out of control.
Never did get around to writing a mudlib, though...
I'm curious to do some performance comparisons, can you perhaps say how one would build and run your code to replicate those benchmark results? (Especially but not only the one you say was faster in LuaJIT?)
In short, I ran C and Lua implementations of the same command, 6 times each, using the built-in "time" command in bash. Averaged the "user" time for each implementation and compared the results. As input, I used a 2m:38.040s long song, 44.1 KHz stereo, converted to a raw file with 32-bit float samples, and I redirected output to /dev/null.
For the first benchmark[1], which was faster for LuaJIT, I actually messed up: I compared the "real" time rather than the user CPU time. But as I recall, the "user" times bore the same relationship, and there was very little deviation among the six trials. If you don't trust me, feel free to do a more rigorous test!
It's worth mentioning that the effect for which LuaJIT beat C was a simple gain, so what was really being tested was a loop that multiplied a bunch of numbers by a (within the loop) constant. The second test in which Lua was a factor of two slower may be more representative.
To build the code, clone the graue/synth and graue/luasynth repos on GitHub. synth includes build instructions, while Luasynth merely requires you to install LuaJIT and run the script.
I've been using Lua in a project for quite some time, replacing Python as my embedded scripting language of choice.
It never ceases to amaze me, as a language and as an interpreter. Sure, the syntax bites you occasionally, and sure, the lack of built-in functionality is occasionally annoying. But hey, I can add callbacks into a simulation engine that execute 10 million times per second with almost no slowdown in the result. Like the article mentions, the string matching library isn't as powerful as Perl's, but it's more than adequate for all of my uses.
My only wish is for an updated LNUM patch that works with Lua 5.2. I deal with integers too much in my projects for its absence to not be annoying.
Roberto did a keynote at the Lua workshop '12, where he detailled what keeps the Lua team busy. A video of it exists somewhere on the web. Half of it was about how to integrate IEEE doubles and 64 bits ints soundly in the language. There are some challenges left, but they're really trying to overcome them.
I recently started programming in Lua too - it's a fantastic language if you want to embed it in anything, and using the LuaJIT FFI [0] makes interfacing with C code from pure Lua a pleasure. I've also started writing a set of extension libraries[1] that provide various "missing" features - mostly inspired by Ruby.
It's very easy to extend Nginx with Lua [1] to create a custom Nginx setup for fast API endpoint authentication, diverting beta users, or handling sockets. I'm hoping to see Lua continue to grow and solve some of its shortcomings like unicode support and pattern matching.
Haven't used Lua much but the concept of tables is really neat. Its simple, orthogonal and the fact it lies at the core of many features in Lua (composite data types, metaprogramming, etc) means those features are neat too.
I agree about the tables. Personally, I find Lua to just be a more honest language, in a sense. Languages like Python or OCaml really just use tables under the hood for objects and what not (from what I understand), but Lua shows you that outright.
It's really annoying when you're working with JSON though. I've used some Lua libraries (the OpenResty stack) where it's close to impossible to generate "[]" because there's no difference between arrays and hashes (and thus an empty table gets converted to "{}").
Well JSON does assume JavaScript semantics, so this type of issue crops up a lot with lots of languages. You should be able to define an arbitrary value that is used as [] by the library fairly easily, or a property of the table.
I think it sorely needs a framework on top that handles and generates the nginx.conf. There's quite a bit "hacking" to get every piece to work with each other (e.g. to talk to a database in Lua it needs to be configured in nginx.conf).
Orthogonal in the sense that the same concept is used if you need maps/arrays or for namespacing functions or metatables(for metaprogramming). Its like a "core" concept that binds seemingly different features in an coherent way. Havent seen a concept used this elegantly in any other language
I find Lua's use of tables as a universal container to be clumsy. For example:
local array = { one, two, threee, four }
A gap is silently created in the array because Lua returns nil for undefined variables. This causes the (#) operator to an return incorrect result and can lead to subtle, difficult-to-find bugs in the program.
Lua makes no distinction between nil and a non-existent element, so assigning nil to an array element will also create a gap, rather than shifting the keys of the subsequent elements downward:
local array = { 1, 2, 3, 4 }
array[2] = nil
-- array is now { [1] = 1, [3] = 3, [4] = 4 }
Your second example is not "clumsy", but a consequence of how Lua's tables are simple and cleanly designed. It would be weird magic for the elements to suddenly shift downward. One can do that oneself if need be.
Your first example has a point – perhaps undefined variables should error when accessed – but that's got nothing to do with tables.
Array keys shifting downward wouldn't be weird magic; it would be the expected behavior when removing an element from an array. Dismissing it as simply how Lua's tables are designed doesn't make it intuitive or expected.
> Your first example has a point – perhaps undefined variables should error when accessed – but that's got nothing to do with tables.
Well, of course it does. The point is that you can silently end up with array "holes" due to a typo, which you are supposed to avoid in Lua for a number of reasons, such as an the length operator returning an incorrect result. I don't understand why my previous comment is getting voted down for pointing this out.
Not implying that one language is better than the other, but how does Lua help solve problems that web developers face? I say this because I have been working on a "killer" web app (JS intensive) for the past few months and it has been a real pain but I dont see how Lua could have helped either.
A lot of people find coroutines easier to work with than callbacks, so there's room for a Lua alternative to Node.js.
The way things are going, it looks like that alternative will also take advantage of Lua's embeddability to allow interop between web apps and web servers in a way that hasn't been widely practiced before.
I've heard of it, but I'm unclear on the benefit. Can't you do async I/O in Lua already? What's the value of adopting the Node.js model, which is mostly about adding I/O to V8 and using callback functions for async, in Lua? (I hope that doesn't sound trollish – I'm ignorant and would like to understand, and the Luvit project page doesn't help.)
Unfortunately, there is a bug in Lua.js and it doesn't support the preferred method of creating modules[1]. For this reason, I've yet to get a substantial size app written. I'd still like to go back and fix this myself eventually, but I was sinking a lot of time into trying to get it to work.
I've been looking for a way to introduce my children to programming.
I've been considering several different languages to start them on and Lua has turned out to be a great choice. My children both love minecraft and we've been writing programs in Lua for the computercraft mod: http://www.computercraft.info/
I agree. I've been teaching my 7-year old son to code and Lua has been a great choice for him so far. After having him play around with Scratch and learn some javascript with Code Monster, we got him going with some game development in Lua with the Corona SDK. It's proven to be pretty intuitive for him and he's having a lot of fun. He was super stoked when we first put his "game" on an iPad and play around with it. I'd definitely recommend it to other parents looking for something to start their kids on.
Having never used a language that indexes from 1 I'd expect that would make a ton of common math used in programming either break or be more complicated.
Pascal and derivatives (Delphi) indexes from 1, and it has pluses and minuses.
For loops are more natural when indexing from one; for loops in most languages specify inclusive ranges, but indexed containers typically advertise their, rather than their maximum index. You don't notice this much in C and derived languages because the for loop in those languages is more flexible (and more open to abuse).
More concretely, this is a very common idiom in Delphi when dealing with 0-based containers:
for i := 0 to list.Count - 1 do
The '- 1' on the end is ugly. What's needed is a way of expressing a half-closed interval, but that's not common in programming languages (despite it being a great aid to correctly expressing many algorithms concisely).
Let's say you want to insert into the middle of an array, at x, with count elements (and presumed free space at the end). You need to move all the elements from x to the end up one. Let's suppose you have a move(array, fromIndex, toIndex, count) function that can do that. In 0-based languages:
move(array, x, x + 1, count - x)
But you need to adjust it for 1-based languages:
move(array, x, x + 1, count - x + 1)
However, you can mitigate it by changing how the move() function takes its parameters:
move(array, startIndex, endIndex, newIndex)
move(array, x, count, x + 1)
If everyone is consistent, and APIs are designed with 1-based indexing in mind, most of the issues go away. It's when there are mixed styles that things get painful.
>What's needed is a way of expressing a half-closed interval, but that's not common in programming languages (despite it being a great aid to correctly expressing many algorithms concisely).
A slightly lesser known construction in Ruby, the ... Range operator does this.
Neither better nor worth by itself, honestly. The reason why it sucks is that integration with C is one of Lua's key selling points: peeking a convention different from C's is a gratuitous pain.
It won't be fixed, because it would break existing programs in too subtle ways. Lua compatiility is sometimes broken, but only if it breaks into easy-to-find-and-fix ways.
I never found it to be a big deal, unless you're trying to copy algorithms from another language nearly verbatim. There's not really any math that relies on 0 indexing,
Eh, for every use case where it's more convenient that arrays start at zero, there's one where it's more convenient that arrays start at one, and vice versa.
For example, to get a prefix of length 'n', you need characters 0 through n-1 with zero-based indexing and 1 through n with one-based indexing. (That Python hides the -1 when using a [0:n] range is a convenience; the subtraction still happens internally.)
Similarly, to get the last element of a one-based array with a[length(a)] and the last element of a zero-based array with a[length(a)-1].
What it comes down to is that sometimes you have to write +1 or -1 for zero-based indexing where you can avoid it for one-based indexing and vice versa. What is not the case is that it only universally happens for one of those schemes.
Good points. I was thinking that there are probably an equal number of array arrithmatic tricks that also require a +-1 here and there, but it was just a hunch. As I said though, never found it to be a problem in practice.
Mathematically, starting with zero is more consistent, because it leads to the fact that the length of a range is the difference between its bounds (length x..y == y-x).
so the 0 vs 1 based indexing is made irrelevant. There are some times where mess up but overall most Lua users don't think its much of an issue. (Personally, I find the lack of a ternary conditional operator much more annoying)
Hmm, weird. It definitely isn't deprecated now, according to the docs[1] and I haven't seen anyone complain about ipairs recently ever since I learned the language ^^. But anyway, the only real downside about ipairs is efficiency so even if they removed it I would probably just add it back myself as a regular function.
Fantastically annoying - an opinion that was sadly beaten in to me rather than being plucked out of thin air. Any language that indexes starting from 1, and can't be configured to index starting from 0, is broken as supplied. Lua makes a number of very poor decisions, in my view, with this being among the worst. I don't think it's quite the worst, but it might be... at index 1, perhaps.
I think ordinary Lua does the same? - this was all a while ago now - but the result isn't arraylike, because the indexes aren't starting from zero. Of course, you can keep on top of the indexes yourself, because tables are tables, and you can use whatever indexes you like and/or track the size by hand... but you might then feel that Lua isn't really being much help here...
The best reason against using Lua in my mind is that undefined variables in Lua return nil, which can lead to typo bugs and therefore unintentional sparse arrays, which screws up the result returned by the length operator. It also has inconsistent boolean expression evaluation:
while 0 do print("Loops forever") end
while not 1 do print("Does nothing") end
while 1 do print("Loops forever") end
while not 0 do print("Does nothing") end
It's nice having real classes in Squirrel with type introspection and corresponding C APIs. In Lua, I have to juggle metatables in the registry to construct a class system, and my system will differ slightly from someone else's. Squirrel's other niceties like compile-time constants, 0-based arrays, and automatic reference counting for predictable memory management overhead make it a quite nice alternative to Lua.
It sounds like I'm bashing Lua here, though I still find it fun to program occasionally. But I do wonder how long Lua can remain as popular as it is with an unconventional syntax, inconsistent behavior, and a minimal built-in library in the face of richer alternatives like Squirrel, mruby, and even Tcl, which has improved much in recent years. There must have been a reason Valve Software chose to use Squirrel in L4D2 and Portal 2 instead of using Lua as most apparently do.
It's not inconsistent at all. In Lua, only nil and false are not true. Everything else is true, including all integer values, strings "0", "false", "", etc.
I'd rather say Lua is one of the most consistent and logical languages when it comes to truth values. You don't ever have to worry about arbitrary value evaluating to false.
Lua's treatment of boolean expression does lead to inconsistencies. For example:
function Func1() return 1; end
function Func2() return true; end
if(Func1() == Func2()) then
print "They're both the same!"
else
print "They're different!"
end
In Lua, even though 1 and true evaluate to true, they're not the same thing and so comparisons between them evaluate to false!
1 and 2 both evaluate to true, yet they're not the same thing, so the comparison `1 == 2` is false. Is that equally problematic to you?
There's no way to avoid this problem in any language that allows coercing a number to a boolean. There are two possible boolean values, and many more possible numeric values. Therefore, numbers that are different and compare unequal will still both evaluate to true. Pigeonhole principle.
It seems you were surprised by the fact that Lua doesn't consider 0 false. Fair enough, that behavior's different from many other programming languages. But there's nothing inconsistent about it.
You're explaining the implementation, which I understand. There are reasons behind everything in the infamous "Wat!" video. The inconsistency is in conceptual expectations: (0) is true, (not 0) is false, yet (0 == true) is false. These are unexpected "gotchas" familiar to experienced Lua programmers.
It's not a dealbreaker. It's just a Lua quirk that often surprises newcomers. I was pointing out that Squirrel uses more conventional boolean evaluation that script authors coming from other languages may be more comfortable with. If you're exposing a scripting API, the language you use is essentially a part of your user interface.
As long as (0) and (not 0) are opposites; and (1) and (not 1) are opposites, there is nothing wrong, inconsistent or surprising.
But I think I see what you are trying to say. You want the == operator to coerce its operands to the same type before comparing (like JavaScript's == operator), but Lua's == operator doesn't do that, it simply compares. And that's why other languages need an === operator and Lua does not.
(JavaScript, by the way is the inconsistent one in this regard: the == operator does coerce its operands, but if(something == true) doesn't do the same thing as if(something). Try it with an empty array)
Lua's behavior here is identical to Ruby's, where 0 is also a truthy value:
$ irb
irb(main):001:0> if 0 then puts "0 is truthy!" end
0 is truthy!
=> nil
irb(main):002:0> if (not 0) then puts "(not 0) is truthy" end
=> nil
irb(main):003:0> if (0 == true) then puts "0 is equal to true" end
=> nil
Many things about many programming languages are surprising to newcomers. However, the rule is very simple (in Lua): In a boolean context, every value besides nil and false is treated as though it were true. It is absolutely consistent. (a == b) is not a boolean context, or else 2 == 3 would be true.
If I understood your comments in this thread correctly what you are calling an inconsistency is that there are many values x for which
if x then print "OK" end
prints "OK" but for which
x == true
returns false. Is that right? If it is, then this is completely normal for languages that allow non-booleans in if statements. For example, x=2 is "inconsistent" in very many languages such as C, Python, Ruby, Perl, most Lisps, etc. I've never heard of this Squirrel language before, but if I read the docs correctly, x=2 is also "inconsistent" in Squirrel. In fact I'd be very surprised by a language that had no "inconsistent" values of x and that didn't achieve this by simply restricting x to be Boolean in an if.
One more language with a C syntax, how so exciting. If for nothing else, I love Lua for taking all the good simplicity out of Python and meshing it with a functional approach and everything is a table. Arguing over syntax aesthetics might be superficial, but I welcome some variety thank you very much, same as I would be bored as a writer if I could only use one style.
Correct me if I'm wrong, but what's inconsistent there is not boolean evaluation, it's number to boolean conversion. 1 == true and 0 == false are pretty standard, but that doesn't mean 0 and 1 are booleans.
Only nil and false evaluate to false. Because there's no distinction between nil and non-existent elements, checking the existence of an element with a value of 0 requires that 0 evaluates to true, so you get this situation:
while 0 do print("loops forever") end
while not 0 do print("does nothing") end
Thanks for posting that link. I've been interested in Squirrel myself and will check it out.
I do like Lua and - per the discussion below - I don't see any problem in Lua's concept of truthiness. It's different from other languages like C or JavaScript, but similar to others like Ruby. Just something you have to get used to if you program in multiple languages.
But the other things you mentioned do sound worthwhile, so thanks!
If you replace 1 with 2 this is an argument against using a vast number of languages, including Squirrel, I think. So maybe you're really saying that languages should forbid non-Boolean values in if statements. Maybe I agree with that.
1 is not the same value as true. Just as in the case I commented on a couple of messages above, 1 and true are two different types.
The == operator does not compare the "truthiness" of two values. It compares the values, and if those values are two different types, they are always unequal.
In my opinion, having (1==true) evaluated to true, but (2==true) evaluate to false is more inconsistent. Even non-professionals should follow logic if they are going to program.
Stop trolling please. You are advocating for `==` doing type coercion of arguments and that is almost always a misfeature in any language that has that (and the fix usually involves adding an ugly `===` operator after the fact)
In the case of Lua rules of what is truthy and why (as I read here) I'd expect (not 0) to be a type error. That's the case in OCaml for example and I think it would be good in Lua.
> The "hash" part doesn't have a defined length. Both parts can be iterated over using the pairs method, which allows you to count the number of elements in them
While true, you should iterate integer-key tables using ipairs and hash tables using pairs.
> No continue statement
Continue doesn't exist? I swear I've used it in Lua 5.1.
Do you really consider that to be a drawback? How often do you find yourself wanting to iterate a datastructure without knowing whether it's an array or a hash?
They changed ipairs around a couple times. It's currently in.
Either way you should be using not-pairs. If you construct a table in a weird way you can end up with pairs going out-of-order. ipairs works fine, also "for i=1,#t" works fine.
I have been using Lua to script the audio sequencer on the game I am writing and it rocks. No performance problems at all, even on an second generation iPod Touch.
And it is very easy to call Lua from C++ and C++ from Lua.
Lua is it's own killer app. It's an excellent choice for embedding, both from a technical (small, pure ISO C codebase, no dependencies) and legal (MIT license) standpoint.
There is now a serious alternative to lua: Jx9 which uses a syntax similar to C and JavaScript and is being used in many commercial games.
http://jx9.symisc.net/
looks more like php than lua. Couldn't see a module/table type of thing? Not sure why I'd use this instead of lua - it's stable and fast. But interested in hearing some reasons
One of the goals of this project was to compile effects code to JavaScript with Lua.js[3] and produce a demo that ran in the browser. There, unfortunately, I ran into a showstopper with a Lua.js bug[4] that breaks my approach to creating modules. Unlike LuaJIT and regular Lua, Lua.js is an experimental project and far less mature - though totally awesome. I might make another attempt to fix the problem myself at some point. With a more mature Lua.js, you could write fast Lua code and port it to nearly every environment.
[1] https://github.com/graue/luasynth
[2] https://github.com/graue/synth
[3] https://github.com/mherkender/lua.js
[4] https://github.com/mherkender/lua.js/issues/13#issuecomment-...