Lua is indeed very, very aweseome -- for all the reasons enumerated, and then some.
But your average Rubyist/Pythonista shouldn't be fooled. The ecosystem of Lua assumes you eat C for breakfast, and if you don't, you're going to be looking around for easy, plug-and-play libraries and wondering why they don't exist.
They don't, because in Lua world, you either call C from Lua or embed Lua in C. You don't throw something together in Lua using the happy friendly libraries that others have written for your convenience (often, in C).
I see comparisons being made with Lisp here and there. The most truthful comparison is sociological: as with the Lisp community, the Lua community (which is very friendly, approachable, and helpful) largely assumes you're smart enough to build it yourself. In C.
If that frightens you, you should probably go back to whatever you were doing before.
> The ecosystem of Lua assumes you eat C for breakfast
That's a bit of an exaggeration. There isn't anywhere near the number of libraries that Python and Ruby have, nor anywhere near the general level of quality, but you can do an awful lot without ever touching C. Reams of Lua code have been written to script WoW by people who have no idea how to program in C. In fact, one of the primary design objectives of Lua is to have a language that's simple for non-programmers to learn.
> you're going to be looking around for easy, plug-and-play libraries and wondering why they don't exist.
That's very true. I spent the better part of a year working on open source web development libraries in Lua but eventually gave up because nobody was using them. There are fantastic libraries in Python and Ruby, at this point it's not really worth reinventing the wheel just to do the same stuff, but in Lua.
The interesting thing about the Lua community is that very few people use Lua as their primary day-in-day-out language, which leads to a distinct lack of fanboyism. I think that's in part why so few libraries exist. The typical Lua programmer attitude seems to be, "Why should I rewrite that in Lua when I can just use the one written in <insert language here>?"
> The interesting thing about the Lua community is that very few people use Lua as their primary day-in-day-out language, which leads to a distinct lack of fanboyism. I think that's in part why so few libraries exist.
Yes. The fact that LuaRocks is close to its 300th library illustrates that :)
I am one of the few people who use Lua as their main language, but I still turn to something else for things like Web development (Python + Flask). Maybe this will change with the OpenResty + Lapis stack [1], which is IMO the most interesting thing in Lua Web development since Mercury [2].
Lua actually has lot of libraries dedicated to interoperability with other languages in a system (protobuf, ZeroMQ, ...), which makes it usable as part of a SOA, so you can write your web frontends in something else and still have most of your backend in Lua.
I primarily do web stuff, apis etc. I wanted to use Lua for a new project and basically gave up. I looked at OpenResty and Lapis and really, really wanted to use it but it was a pain to get working and pain to keep working. Not sure if it has matured since the last time I looked at it (2-3 months ago), but at the time I couldn't use it without quite a bit of mucking around.
That said, I would still love to use it if it was even close to ready.
It is improving fast these days. If you have used it months ago it was 0.0.1 and now it is 0.0.3. Still, those version numbers should make it clear you should not use it in production for something serious...
OpenResty itself, on the other hand, is perfectly usable and used in production at large websites such as Taobao (the Chinese eBay / Amazon) and CloudFlare.
> Reams of Lua code have been written to script WoW by people who have no idea how to program in C.
That plays into one of the reasons why there's not a lot of Lua libraries: they're mostly ecosystem-specific. There's quite a few Lua libraries for WoW that aren't inherently tied to WoW, but they aren't packaged in a way that makes them usable anywhere else. People writing code for a specific program that happens to use Lua generally can't use libraries from LuaRocks, so there's no reason for them to care about LuaRocks in any way.
Sadly I'm not sure that there's really any solution to this problem other than just accepting that an embedded language will have a very fragmented ecosystem.
There is much more of a web development community starting to grow in Lua now, largely around openresty. As a community (especially a web dev one) we need to do more to curate and distribute (and document) these. So do try again!
But is that the attitude the community should be taking? Why can't it be both? In fact it would doubly-awesome if that were the case because having a language that has great support for C but can still be used with ease is a gap most languages fail to close because they choose the binary one or the other.
Really, its one or the other by necessity. The things that make a language good for embedding are the opposite of what you want in a general purpose scripting language. Its also unlikely for any language to build great support for c unless thats the purpose of the language (ie, embedding).
Lets consider Lua. Lua uses a prototype based inheritance system and coroutines for concurrency and has basically no standard library. Anyone who uses Lua extensively ends up building their own object/class system in addition to filling out the standard library. This makes sense; an embedded language shouldn't force its object model on its host and it doesn't need a standard library. The host most likely comes with a standard library of its own. The lack of common building blocks and the reliance on external code means Lua will never be a general purpose scripting language because its just too damn hard to reuse code.
The things that make a language good for embedding are the opposite of what you want in a general purpose scripting language
I'm not sure I agree. What you want for embedding is something small, fast, and easily interoperable. What you want for general-purpose programming is powerful, composable abstractions. Lua meets both sets of criteria. It does so by means of exceptionally good design. The fact that it doesn't have the same object model as some other languages doesn't really prove anything, does it? Every well-designed programming language deserves to be thought of on its own terms.
Not having a featureful standard library, on the other hand, certainly is the kind of tradeoff you're talking about. But (a) is it so important to have a standard library as opposed to just pulling in the libraries one needs? and (b) you may be overestimating the difficulty of interfacing with external code in Lua. It's much easier than with other dynamic languages. "Too damn hard" seems an overstatement.
The big question with Lua is whether it's better enough than its peers to overtake them in any area other than embedding. If it is, we should see some sort of killer application of Lua. There is momentum toward an embedded-web-app style a la OpenResty, but also still a high barrier to entry; for one thing, it isn't well documented.
Just like javascript, building an inheritance-based object system in Lua is pretty much the sign that you are fighting the language, rather than using it as it is.
Unlike in javascript, it's possible to build an inheritance-based object system that works almost exactly like Python's in Lua. It's actually a bit trivial. Considering that the language is generally not opinionated even regarding the features it ships with ("you can use 0-based arrays if you want"), this doesn't seem all that bad.
As noted above, when everyone rolls their own object system, integration gets messy. I think it's easier to stick to the basics of using functions and tables.
My favorite thing about Lua is that the language is so simple, once you figure out one way to do something it's probably the only way. Like, say, summing up all the numbers in a list of strings. In Perl there are many ways, in Python there are many ways but one is right, and in Lua there's probably only one way so once you figure it out, you're done. Simplicity is a nice thing in an embedded tool language.
Lua is a really simple language, and is quite malleable to different use cases not included in the language per se. Usually in my book, it is an advantage, for example how many Lisps can implement new features that seem like language features, but aren't.
But this simplicity can have a downside, as there might not be canonical ways of doing things that users are accustomed to. For example, object orientation. It could be a hard sell to someone coming from an object-oriented language, when you have to understand, and choose between multiple different styles of object-orientation and implement them consistently in your project, or use one of the many libraries made just for this. For example, see http://lua-users.org/wiki/ObjectOrientedProgramming
It is a bit nice to not be limited by any particular OO system. I don't get much use out of this, since my current class.lua is about 14 lines and doesn't do inheritance, but it would be easy to add in the future. It's probably a bit easier for people with js experience to get used to OO in Lua. Coming from js, most of the language just seems like a copy with more expressive power and fewer mistakes.
As a huge Python fan, comments like this(and many others) have made me want to check out Lua. Is there a canonical Lua introduction out there? I'd love to give it a try.
Really an awesome book! It not only teaches you about the programming language itself, but also how to use it well and idiomatically. Also, it is very focused and compact, which is a great thing in a programming book--although it makes for kind of a dry read.
function curry(f,x)
return function(...)
return f(x, ...)
end
end
function reduce(f,t,r)
r = r or t[1]
for i=2,#t do
r = f(r,t[i])
end
return r
end
addf = function(a,b) return a+b end
sum = curry(reduce, addf)
t = {"1", "2", "12"}
print(reduce(addf, t)) -- 15
print(sum(t)) -- 15
res = 0
for i=1,#t do
res = res + t[i]
end
print(res) -- 15
res = 0
for k,v in ipairs(t) do
res = res + v
end
print(res) -- 15
No, but I think a lot of python users consider this a particularly compelling advantage as readers.
At least, I know I sure spend a lot more time reading code than I do writing code; so I appreciate any language that tries to optimize for that use-case and helps me minimize my cognitive overhead.
* Lexical scoping
* Tail-call optimization
* First class functions / closures
Lua is not a functional programming language but I tend to have a large number of closures and recursive functions in my Lua code. Lua's limited feature set means that you end up using closures as a replacement for things which are special features in other language.
Here is an example of a closure doing the job of C/C++'s function-scope static:
Note that a closure is more efficient than function-scope static here. The static requires a "is initialized?" check every time the function gets called, the closure does not.
Lua's function definition syntax is really the best one I have seen yet. One simple statement that combines all the flexibility of lambda and def (in Ruby/Python-speak). I wish Ruby and Python had a powerful statement like that.
The features mentioned, along with coroutines and coroutine.clone, allow the creation of more or less any control flow the user could want. It's a total breeze to use.
Is Closure(function ... end) really an improvement over the normal IIFE look of (function ... end)()?
do
local move = {
[Direction.up] = View.Up,
[Direction.left] = View.Left,
[Direction.right] = View.Right,
[Direction.down] = View.Down
}
function View.move(self, direction) move[direction](self) end
end
Random performance note: in the default lua interpreter, the fastest objects are the ones implemented as closures. Unfortunately, it has higher memory requirements and is rather ugly.
One problem I have with Lua is that it silently returns nil when accessing non-existent elements. There are a few hacks around this, but the most common only protect global access. I have to wonder why the language reports no error in that situation given that it does report an error when comparing values of different types (no automatic conversion) or when attempting to index nil.
It is the norm (for larger projects) to use a "strict" script which prohibits the use of undeclared globals. As far as local nil access is concerned, it is necessary for idiomatic Lua.
For example, this is how you implement optional arguments and default values in Lua:
NeumannNeighborhood = function(position, extent)
extent = extent or 1
...
end
Here extent is optional and its default value is 1. That's how you keep a language small.
extent is declared, not defined. You wrote "accessing non-existing elements" .. extent may not exist in my example.
And as I said bigger Lua project usually use a script which prevents the use of undeclared globals. Such a script would detect the bug in your example because "extant" is a global and undeclared (variables are global by default in Lua).
It's declared and defined in the function argument list, assigned nil if no argument is passed for it. The problem with prohibiting the access of undefined globals is that your tables remain unprotected. If the value of "extent" was retrieved from a table argument using an incorrect key, the mistake would go unreported.
>It's declared and defined in the function argument list
No, it isn't. No value is ever assigned to "extent" if the function gets called without a second argument. "extent" is nil just like all other non-existing objects are nil.
It is a common newbie mistake to treat Lua's nil as the equivalent of a null pointer or some kind of "nothing value" you find in other languages.
Lua's nil is not a value of any kind. "object = nil" means "delete object" not "set object to nothing value". Because of that you should never assign nil to anything unless you actually want to delete it. Delete as in "garbage collector please pick this up". E.g.
character.armor = NULL
in C does not delete the armor field of the character struct.
character.armor = nil
in Lua does.. and you probably don't want that in such situations because if you handle it this way you create countless unnecessary allocation, reallocation, and deallocation operations behind the scenes. If you just mean "nothing here right now" you should set the field to "false" or some specific nothing value.
>If the value of "extent" was retrieved from a table argument using an incorrect key, the mistake would go unreported.
That is correct and a problem indeed. However, in my experience such things rarely happen and the resulting bugs are easy to find.
> No, it isn't. No value is ever assigned to "extent" if the function gets called without a second argument. "extent" is nil just like all other non-existing objects are nil.
If you prefer the Lua concept that all possible elements start out pre-set to nil, then again, "extent" is already defined. Whichever mental approach you prefer, the variable "extent" exists in your example.
> Lua's nil is not a value of any kind. "object = nil" means "delete object" not "set object to nothing value". Because of that you should never assign nil to anything unless you actually want to delete it. Delete as in "garbage collector please pick this up". E.g.
This isn't correct. Nil is a value type, and it exists solely to be different from any other value. Lua tables are presented as containers in which every possible key starts out already assigned the value of nil. Nil doesn't explicitly mean "delete object". Rather, a table variable is a reference to a table object, so assigning it a value of nil removes the reference and makes the object available for garbage collection (if nothing else is referencing it).
In other words, the reason Lua makes no distinction between non-existent elements and elements assigned to nil is that, conceptually, every possible element already exists and starts out assigned the value of nil. Therefore, when I use the term "non-existent", I'm speaking in practical terms from the perspective of the programmer. You presented to me an example which you claimed would no longer work under the behavior I proposed, but the "extent" variable would be both declared and defined in the function's argument list, so the "default argument" behavior would still work. The variable would just be assigned the value of nil if no argument was passed for it.
I'm not sure why you're offering these explanations except to make it appear as if I don't know Lua. I presume you're the one who voted down my previous comment.
> That is correct and a problem indeed. However, in my experience such things rarely happen and the resulting bugs are easy to find.
To the response that it just doesn't happen that often or that the bugs can be easily fixed, I would point out the existence of several Lua static analyzers and direct you to Google's own analyzer (http://code.google.com/p/lua-checker/), with this project description:
"Lua is dynamically typed, with a simple type model. Variables can be assigned values of any type. This makes development of small scripts somewhat easier, but it means that in larger programs many common programming errors are not detected until run time. For example:
- Referencing a variable that has not been declared will return nil. This is no different from referencing a 'declared' variable that has the value nil. Thus spelling mistakes in Lua variable names can go undetected and lead to program misbehavior.
- Tables (Lua's main data structure) are not typed, so any table can contain any keys. When tables are used in a manner similar to C structures, spelling mistakes in field names can go undetected and lead to program misbehavior.
- Function arguments and return values are also untyped and have similar problems.
In practice, Lua programs over (say) 1000 lines tend to accumulate these kinds of problems, making debugging difficult."
It's because accessing a variable means looking up a name in the global environment, which is technically just a table. Since it's just a table like any other, any non-set key has nil as its value.
You can actually access said global environment as the _G variable.
Now, you could totally stick a metatable on _G that caused some sort of exception when you tried to get the value for a key with a nil value.
I understand the reason for the behavior--Lua pretends that new tables start with all possible keys set to nil. I find it regrettable because it necessitates static analyzers for larger projects and contributes to a lack of safety, especially since the language is targeted at non-professionals and hobbyists. With multiple contributors to a project, one typo can lead to unintended sparse arrays and hard-to-debug errors that propagate far from their origins. The behavior seems inconsistent with Lua's existing policy of raising errors for attempted indexing of nil and for order comparisons of different types of values.
The issue was raised on the Lua mailing list, and the response from one of Lua's curators was, literally, "I used to make mistakes like that, but then I got used to it." Lua is admirable for its size and speed, but I believe that it's sometimes too conservative about changing historical behaviors to accommodate safer policy.
Wow, accidentally putting holes in the middle of a numeric table sounds nasty. These issues don't bite me very often, but they are pretty easy to prevent.
function a_stricter_table()
return setmetatable({}, {__index = function(t,k)
error("no value at "..tostring(k))
end})
end
t = a_stricter_table()
t.a = 5
print(t.a) -- 5
print(t.b) -- crash D:
A similar trick can make trying to unset a value by assignment raise an error, while unsetting a value using a delete() function is allowed.
Edit: Removed the fake table/backing table thing, since you can do the one trick without it. I think the other trick requires it, though.
Array holes can be quite nasty, as they lead to incorrect return values for the length operator. Protecting individual tables with a custom solution, on top of prohibiting undefined globals, naturally makes one wonder why the language doesn't behave this way natively. Lua is praised for being unafraid to break backwards compatibility in major releases because embedders can retain their existing versions of the codebase indefinitely. This seems like an opportunity for a future version.
It doesnt because there are cases when you want that behaviour and the language gives you tools not policy. In a serious project pretty much every table will have a metatable anyway.
It is mostly the same, though in my experience it is easier to stop this in Lua than in JS (just attach a metamethod to the globals table to raise an error on lookups for keys with undefined values... this is similar in practice to JS strict mode).
I'd add that most worries about silent nil returns stem from not accepting Lua's very clear value semantics; nil literally means "undefined value" (as compared to JS's null or Python's None); setting a variable to nil is the idiomatic way to release its value for garbage collection.
So "silently returning nil" is more like "explicitly returning notice that the value is undefined". Whether you want that to be an error-raising-event or not is up to you, the programmer. And it's easy to control that error-throwing behavior in a granular way; you can attach the error-throwing metamethods to the globals table, or to specific tables you care to protect.
Does that make it like Objective-C because I love how accessing a null object doesn't blow up the application. So many trivial bugs in my iOS app that would have caused the entire application to crash are totally avoided. Unless you're creating software for the space shuttle, avoiding null exceptions entirely is a god send for my users.
Strongly disagree. You should fix trivial bugs before you ship the app, and Objective-C silently hiding them from you makes that much harder. It's one of the things I hate about Objective C. Makes it seem more like PHP with warnings off.
Ethical programmers don't want to deliver programs to users that are riddled with unknown, undetectable bugs, that silently corrupt data and make mistakes, without being caught by testers or warning the user.
That's why it's better to be bold and crash spectacularly, instead of trying to cover up unexpected problem by guessing. If you have an unexpected null pointer, there is a reason, and your expectations were wrong, so there's something bad going on that you don't know about. By silently hiding the problem, your program may be doing the just wrong thing, and you never know about it.
That's the problem with PHP, which has it even worse than Objective C. Ignoring errors and guessing what to do is PHP's way of life, and it's been the cause of countless security holes, data corruptions, and hard to diagnose bugs.
Use lots and lots of pedantic asserts, and test thoroughly, so the production code does not have to be riddled with labyrinths of error handling and mitigation guessing code. Assume the APIs obey their contracts, and write APIs with strong contracts that do what they promise. If something might return a NULL, then test for it and handle it properly, so whoever is reading and maintaining your code knows that you considered the possibility and thought through the solution, and the computer doesn't have guess what to do.
Computers are notoriously bad at guessing the programmer's intentions, so programming languages should not encourage programmers to let the computer guess what they meant.
I don't purposefully release software with bugs. Bugs are inevitable no matter how good of a programmer you are. Like I said, would you rather your browser crash on every javascript bug? Because that's how a lot of client side software operates.
You're not getting it through your head, or comprehending what I am saying, so you obviously have no experience as a professional software developer. Your software will have a lot more bugs in it, and is a lot more likely to corrupt your users' data, if the language you use conceals the problems from you during development and testing, and guesses at what you want. Go back and read what I wrote, and address those points instead of ignoring them. You are incorrect that it's better for a programming language to hide errors, guess what you meant, and silently corrupt data. You may think that it's convenient for you not to have to type the extra keystrokes to check for unexpected null pointers, but that is because you are a lazy programmer who would rather save time and cut corners than write reliable code.
It's not like Objective-C, which returns a nil value when sending a message to nil. Lua, on the other hand, throws an error when attempting to index nil.
Big fan of Lua. I have only poked around at the language, and never really done anything significant with it, but I love how simple and powerful it is. Every time I break out the lua programming book I wish I were using that at work instead of python. I don't agree with every choice they've made, but it's a great language for sure.
Years ago I read a Lua tutorial but I didn't like the language much.
Nowadays I am working on a large 99% Lua code base and I love the language! Lua has a small set of building blocks and only if you try to write something non-trivial in Lua you realize how incredibly well these blocks fit together.
It's funny, Lua is the opposite of Go for me there. I was excited about Go after reading the tutorial, but then I tried to seriously use it the experience was underwhelming.
Same here: I once wrote a bunch of simple plugins for Renoise in LUA which was my first (and so far last) contact with it.. I forget everything about it since then, other than that it was very fun! I spent time learning the Renoise API and figuring out UI stuff, LUA itself just kinda worked. It was like jumping into cold water and finding it rather warm and pleasant.
Lua is quick. OpenResty and nginx are certainly providing a very high performance ceiling, but the test is indeed Lua code [1]. Many test implementations for other dynamic languages are similarly provided a high ceiling by nginx but then fail to deliver on that potential.
I would be interested to hear anyone's experience using luaj on Android (thats where I plan to use it), and how it may compare to other options like Rhino.
I never got past initial investigation of kahlua and luaj. However, they were appealing because I had a large server application based in Java that utilized spawning off other processes to help map/reduce data. We had written Lua scripts to do these helper tasks. But because of the Java, it was very expensive to spawn off other tasks, because they also needed to be wrapped in Java and starting a new Java instance ate a lot of memory and had a slow start up.
The idea was to use kahlua or luaj to do the same helper tasks within the main process so other Java instances wouldn't have to be spawned.
But for Android, plain old C based Lua works great with the NDK. There is also LuaJava and JNLua which can cross the native/Java bridge.
I concur it is probably not a good idea. I know from other benchmarks that Dalvik in general has terrible performance and adding a layer on top of it is just going to make it worse.
I love Lua, it's definitely underrated. My first experience using Lua was via Indigo Rose Setup Factory, it uses Lua for scripting installer logic and the thing I love most is how easy it is to learn (even easier than a language like PHP). A few hours and you've grasped most basic concepts and conventions, if you already know another language you'll find the learning curve further reduced once more.
You'd need some libraries before that was comfortable. At the very least you would want to install LFS (Lua File System), for things like checking if files exists and what permissions they have. If Lua string patterns don't cut it for your text munging needs, you would want another library, either a regex library, or, even better LPeg. Even with those things, things like running several commands connected by pipes is not going to be as convenient as in sh or even Perl.
If I needed an embedded scripting language for a project I'd reach for Lua without a second thought.
I've been strongly tempted to use it for actual core app development but every time I look at it the scarcity of common libraries compared to something like Ruby or Python cools me off.
It would be great if one could use Lua as general purpose language. The missing part is the lack of a bigger official standard library. Several addon libraries that try to fill the gap are outdated, unmaintained and/or not of the same high quality code as Lua and it's official libraries. The Lua community would also benefit from an website that has unified documentation and comment functionality like php.net and Ruby Gems or Node.js NPN repository functionality. (I know Lua has a Wiki and repository ...but sadly, they look very dated, its features are from last century).
Using Lua as embedded language is great though, especially with LuaJIT2 it is top notch. Interfacing with C is easy. C++ requires a bit of research as there are several possibilities (e.g. third party wrappers).
coroutines in lua a great for game development. Also the reference, luajit and one more commercial that I've seen are all based on Lua state object, rather than global data (python?).
And luajit is more alien technology than common lisp :)
It just works (for code written to Lua 5.1; it's about 95% compatible with Lua 5.2, which changed how modules work) and can pretty much replace Lua (either the standalone executable, or linking it as a library). The "alien tech" probably comes from how it works, converting Lua to native code. I can't say how difficult to understand, since I haven't really looked into the internals, but from what I understand, Mike Pall created a new way of looking at assembly language as part of LuaJIT.
It was a pun on Common Lisp (great language btw) - http://lisperati.com/logo.html
But then after seeing LuaJIT2 I think there was something even more alien. It made me understand that I don't know programming very well after seeing what Mike Pall did there.
Adobe Lightroom is about 40% written in Lua (the stat comes from Wikipedia). IIRC C and C++ are used for image processing and compute-intensive stuff, but the rest of it is all Lua. I believe that would be the most widely used app written mostly in Lua, though Apache, Redis, Nginx, Vim and some other big projects support using it for scripting.
Also note that Lightroom was written before LuaJIT was really a thing; had LuaJIT come first there might have been even more Lua in Lightroom. Like World of Warcraft, Lua also provides a plugin system in Lightroom (but very few people use it or even know it exists).
VLC, MySQL (and MySQL Workbench), Wireshark, AwesomeWM, NMAP, NGINX, Ogre, CEGUI (and most corporate game engines), OpenWRT, Recent TI calculator (bye bye TI basic)
Many more, but it is what come to my mind right now
Games can't be emphasized enough. Grim Fandango and Escape from Monkey Island in the late 90's were the first known corporate games that used Lua. After word got out at GDC, the entire industry started using Lua. Big profile hits like World of Warcraft and Angry Birds make Lua sound like something new in the video game industry, but Lua was already de-facto standard. If you buy a game today, there is a greater chance that it uses Lua than it not.
Nothing is pure lua, you could probably use GObject-introspection to write a GTK app, but nobody do it.All of these apps have _some_ lua code, but it is nowhere close to 10%, I will give you that.
While I cannot pretend it is significant, it is new/fresh/recent. I'm just going through a transition to the GMime mime library, but beyond that the code is stable and I've used the client for the past few month or so, replacing mutt as my main client.
Now that I'm using it I'm finding interesting things to do all the time, using Lua has allowed me to move from having a mostly-extensible client (mutt) to having a __very__ extensible client.
Lua is an industry standard in the video games business. The scripting language used is usually Lua or Python. Examples of Lua-scripted games: Civilization V, King's Bounty, SimCity 4, Dawn of War, Crysis etc.
A lot of WoW itself seems to be written in Lua. A bug in Lua would occasionally allow a cheats in WoW, so it got heavily tested by motivated folks. I'd call that a significant deployment.
It's more fair to say that a lot of the UI for WoW is written in Lua, and most of the API available to that UI is also available to addons that end-users write for the game.
Scheme's a very decent language too, but so far I haven't found any scheme implementations out there which are anywhere near as good as Lua—small, portable, highly efficient, robust, easy to integrate [with the "underlying" program], well maintained, good and active community, etc—for this space. The most popular scheme implementations tend to be enormous, despite the language's historical reputation as a "small" language.
Lua's a great language, but the amazingly good implementation is as much (or more) a factor than the language itself.
Scheme is fine if your goal is only to have a small section of the programming community want to use it. Lua is great for everyone, including people who have never coded before in their lives as well as experienced software developers.
But your average Rubyist/Pythonista shouldn't be fooled. The ecosystem of Lua assumes you eat C for breakfast, and if you don't, you're going to be looking around for easy, plug-and-play libraries and wondering why they don't exist.
They don't, because in Lua world, you either call C from Lua or embed Lua in C. You don't throw something together in Lua using the happy friendly libraries that others have written for your convenience (often, in C).
I see comparisons being made with Lisp here and there. The most truthful comparison is sociological: as with the Lisp community, the Lua community (which is very friendly, approachable, and helpful) largely assumes you're smart enough to build it yourself. In C.
If that frightens you, you should probably go back to whatever you were doing before.