Lua vs Ruby benchmarks (similarly "high-level" languages, insanely different performance)
shootout.alioth.debian.org
shootout.alioth.debian.org
But even though both are dynamic interpreted languages, it's still apples to oranges - they have very different design goals.
Still, I think it's a copout to say performance doesn't matter in any general-purpose language the way the core Ruby team seems to. Micro-optimization is a waste of time, but efficiency and intelligent implementation choices are necessary.
In practice (not micro-benchmarks), I've found LuaJIT to be at least twice as fast as the standard version, and in some cases three or better.
SBCL is faster still, averaging about half the speed of GCC and about the same as Java.
If you use Lisp’s static annotation
system, your code becomes uglier than
Java, and much less safe (I don’t think
Lisp does static checking of parameter
types, it just goes ahead and passes you
an object and lets you think it’s an integer).
Additionally, Lua only has "one data structure type" - that's also "higher-level" than what you have to do in Lisp, deciding among singly-linked lists, arrays, hash tables, binary trees, lexical trees, etc.So while SBCL has its place, there's something about Lua you have to admire, don't you think?
Short paper, but very interesting.
The LPEG paper (http://www.inf.puc-rio.br/~roberto/docs/peg.pdf) is great, too.
Similarities: Block/lambda support and syntax, optional parentheses, control statements as block, prefix, or postfix.
OTOH, "how come Lua is not as widespread as say, Python ? I'd say the answer is this: there is no real standard library, and as opposed to Python, Lua doesn't come with batteries included." -- http://www.ivy.fr/blog/index.php/2008/03/17/83-kahlua-lua-on...
On the other hand, interfacing to C is the nicest of anything I have done, by a long shot, so the lack of batteries isn't that painful in practice. It fills a different niche than python or ruby, in its, it shines.
Thus, I feel a Lua - to - Ruby/Python comparison is sort of erroneous. Use Lua when you already have all your tools. Use Ruby/Python when you don't have any tools, and you want cool whizbang higher-level stuff.
Honestly the benchmark is wholly unsurprising to me; Lua is a much more minimal language. If you need another language to lump Lua with, lump it with Javascript sooner than you would Ruby or Python.
Look at LuaRocks (http://www.luarocks.org/). It's an attempt at a CPAN-like package collection. The stdlib and bitlib libraries, in particular, are pretty necessary. (Also, http://www.tecgraf.puc-rio.br/~lhf/ftp/lua/ has some others.)
Lua errs on the side of only putting what can be implemented fully portably in ANSI C in its standard libary, which makes it a bit spare.
To get started with Lua, I'd recommend PIL: http://www.lua.org/pil/
For example, Lua's use of two dashes for line comments, and --[[ and --]] for block quotes. That lets you remove the first --[[ in a block quote without causing the program to break, because the "closing" block quote is commented out at that point (because --]] is a comment at that point). But really, that's so different from other languages that it seems like a liability rather than an asset. That's what I meant by "not necessarily beautiful". It is definitely beautiful in certain other aspects, though.
Also, if I were writing a scripting language, I'd love for it to be "like a prostitute". Even if nobody respected it, everyone would be using it.
By that metric, PHP is the scripting language for you. ;)
The double hyphen comment is used elsewhere. SQL comes to mind.
Tables in Lua can be thought of as discrete mappings of any value as key, to any value as value. The reference implementation happens to have the property that if you index from 1 upwards by increments of 1 that all of those values are kept in a single C array which is then subscripted in the usual fashion. It's a handy thing to know when you decide how to lay out your data. The "dictionary" portion of the table only springs into existence when something is actually inserted into it.
Actually if I understand correctly, an empty Lua table is basically just a pointer to a minimal structure in memory, so it can be used for identity comparisons and so on where only uniqueness is necessary, rather than a full array+dict functionality with the associated memory overhead.
Lua tables are extremely flexible and powerful. Especially when combined with the "metatable" concept.
That does not always hold true. The '#' operator is weird. Here is an example:
Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> x = {1,2,3}
> x[1] = nil
ipairs() stops at the first nil, as expected: > for i,v in ipairs(x) do print(i,v) end
However #x is inaccurate now: > print(#x)
3
Luckily, we can always see all the values with pairs(): > for k,v in pairs(x) do print(k,v) end
2 2
3 3
And watch what happens when we add a single non-integer key to the array: > x.a = 10
> print(#x)
1
>
Looking at http://www.lua.org/source/5.1/ltable.c.html#luaH_getn I think the problem lies in the assumption in luaH_getn that if the table doesn't have an 'hash' part then it also doesn't have any gaps. /*
** Try to find a boundary in table `t'. A `boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
int luaH_getn (Table *t) {
unsigned int j = t->sizearray;
if (j > 0 && ttisnil(&t->array[j - 1])) {
/* there is a boundary in the array part: (binary) search for it */
unsigned int i = 0;
while (j - i > 1) {
unsigned int m = (i+j)/2;
if (ttisnil(&t->array[m - 1])) j = m;
else i = m;
}
return i;
}
/* else must find a boundary in hash part */
else if (t->node == dummynode) /* hash part is empty? */
return j; /* that is easy... */
else return unbound_search(t, j);
} > x.a = 10
> print(#x)
0
>
Which makes more sense than 1. At the same time, 3 is also a valid value of #x, because it is the integer index of a value directly preceding an index with a nil value.This behavior has been hashed over on the mailing list multiple times... the exact wording of the documentation allows for it but it's not exactly what people expect of the length operator.
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero. For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value. If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider _any_ such nil value as the end of the array). -- From the manual
My expectation is that there will be some changes to the handling of the # operator in 5.2 increasing its usefulness and allowing it to be overridden via metatables for user-defined types.
In any case, this is one of the few currently ugly corners of the language itself. Another would be the handling of destructuring varargs via the select(...) function, which can be really funky.
What version of lua did you use? Perhaps my version's # is buggy in addition to being weird.
# works with an array-style table (consecutive integer keys, starting from 1) and not hash-style tables. Once you're familiar with Lua, you rarely confuse them -- they tend to be used very differently. Using the same variable type is mostly an efficiency trick.
I agree that counting from 1 is kind of annoying, but part of their reasoning was that Lua is targeted as a scripting language for niches that can include people who don't really program. They tried to keep "weird" programming stuff from obfuscating the tiny amount necessary for writing config or data files in Lua. It has coroutines, lexical scope, metatables, etc. when you use it for real programming, but they don't get in the way when you don't need them.
For example, from the data file for my laptop's wifi script:
device="ral0"
sudo=true
Network { key="home", nwid="barbelith", wpa="..." }
Network { key="sparrows", nwid="The Sparrows" }
Network { key="schulers", nwid="schuler-alpine" } Lua 5.1.3 Copyright (C) 1994-2008 Lua.org, PUC-Rio
>
This is using the Lua console installed by the the (excellent) Lua for Windows package.http://www.cs.utexas.edu/users/EWD/ewd08xx/EWD831.PDF http://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EW...
if i parsed it correctly, he is saying that things should be 0-indexed because a particular mathematical notation corresponding to it is more sensical, but i don't see what mathematical notation has to do with programming notation, both of which are man-made, arbitrary, and for different purposes, such that reasoning about either with respect to the other is imo fallacious
he compares subscript ranges in a notation where 0-indexing appears to be better, but choosing a different notation (such as b in his examples) makes it look better for 1-indexing ( 0 < i <= N versus -1 < i <= N-1 )
Extensive experience with Mesa has shown that
the use of the other three conventions has been
a constant source of clumsiness and mistakes
0-based indexing is not something you can rigorously prove to be better.and while we're considering sources of "clumsiness and mistakes," 0-indexing is an exceptional candidate, from my experiences helping a friend learn C++ and my own memories treading through those early days
i look at it from the perspective of usability
for (elementIndex = first-element; elementIndex < indexAfterLastElement; elementIndex++) {
...
}
That is, writing the equivalent of the mathematical notation: firstElementIndex <= elementIndex < indexAfterLastElement
Two advantages of that idiom:The first one is that indexAfterLastElement - firstElementIndex equals the number of elements being scanned.
The second advantage (which is the most debatable, and personal) is that the initial boundary condition is trivial (it's the first element) and the end boundary condition is natural i.e. just look past the element you are looking at whether there is a next one. That's what Dijkstra is talking about when telling the example of the student who would not look past the end of the page.
I used the epithet natural because for most of the objects we interact with, the end is not part of the object, rather it is the transition in between the last element and nothingness.
Now that said (in too many words) if you compare 1-based arrays and 0-based arrays you have:
for (i = 0; i < N; i++) {
...
}
for (i = 1; i < N + 1; i++) {
...
}
Both would be acceptable. However 0 based arrays have the advantage of giving i two meanings: 1. the index of the current element
2. the number of elements scanned so far.
At the end of the iteration, i also conveniently contains the number of elements having been scanned. Which can be useful in algorithms where there is an extra condition which might let you leave the iteration early.This to me is the most important part, zero-based indexing is more expressive.
In many cases I don't care about specifying boundary conditions at all; I will just use something along the lines of
for i, v in ipairs(t) do something_interesting(i, v) end
or even just a map or fold or some other iteration technique where I'm not explicitly specifying boundary conditions. If I'm implementing a heap or some other data structure which uses calculations to interact with an array I will be double-checking my math anyway because I don't trust myself to get it right the first time, 0-based indexing or not ;)the [[ and ]] can be extended to nest strings/comments like so:
--[==[
function add( a, b )
--[[
return a + b
]]
return a - b
end
]==]
you can use [=[ ]=], [====[ ]====] etcMost lua codebases I have seen tend to be written in what I call an "imperative functional" style, where the language isn't purely functional, but functions are the most common means of abstraction.
It has proper anonymous functions, lexical scoping, etc so you can write very rubyish code (such as moonunit http://svn.apache.org/repos/asf/httpd/httpd/trunk/modules/lu... and using it http://svn.apache.org/repos/asf/httpd/httpd/trunk/modules/lu... ).
In short, Lua's philosophy is to keep the core language as small as possible, but to include features that make it easy to add major language features as necessary. Adding an object system to the language is trivial, for example. (It doesn't have hygienic macros, though there are some side projects that attempt to add them. No experience with them, though...I'd just use Scheme.) Lua feels to me like a minimalistic, more internally consistent Python.
Results look almost the same ;-)
http://shootout.alioth.debian.org/u32/benchmark.php?test=all...
Lua is generally the fastest scripty language, ruby is generally the slowest. Ruby is much more general purpose though -- Lua is very optimized for embedding.
Better yet, LuaJIT is a drop-in replacement. There's no reason not to use it, as far as I know.
LuaJIT 1.1.4 Copyright (C) 2005-2008 Mike Pall
ruby 1.8.7 (2008-08-11 patchlevel 72) [i686-linux]
Although I doubt it's going to ever replace PHP I think it's poised to make some inroads now that the next version of Apache will include mod_lua out of the box.
(AFAIK, just seen references to all this).
I think Ruby in general is less amenable to analysis/compilation than Lua is, so even a JITed Ruby might not do as well as Lua.
http://shootout.alioth.debian.org/gp4/benchmark.php?test=all...
so, i'd take it with a huge slab of salt.
http://luajit.org/luajit_features.html
Since it is able to use certain non-ANSI C features on the various platforms it supports it can do other neat things like enable coroutine calls across Lua/C stack boundaries.