Hacker News new | past | comments | ask | show | jobs | submit login
A History of Lua (2001) (lua.org)
141 points by atan2 on Aug 10, 2022 | hide | past | favorite | 120 comments



My favorite feature of Lua is that it tells you who all of the complexity-loving people in the room are and those who enjoy syntax monocultures.

Almost every single time, without failure.

I consider its simplicity and the fact that people merely complain about its syntax as highlights of an extremely thoughtful piece of software.

I have complaints about its use for threaded work as well as performance, but it’s relatively hard to run into issues with the language in regular practice.

I don’t buy the lack of types argument in any programming language to be a compelling argument. Maybe consider that you or other authors you’re working with are bad at writing software. It’s a more boring conclusion and more often more accurate.


>I don’t buy the lack of types argument in any programming language to be a compelling argument. Maybe consider that you or other authors you’re working with are bad at writing software.

I don't buy the lack of seatbelts argument in any car to be a compelling argument. Maybe consider that you or other drivers you're driving nearby are bad at driving.


> I don't buy the lack of seatbelts argument in any car to be a compelling argument. Maybe consider that you or other drivers you're driving nearby are bad at driving.

Types are a good idea of many languages, but not a universally good idea.

I love your seatbelt analogy. Since seabelts are a good feature of cars, this does not mean at all that they would be a good feature for sailboats. Or for bicycles. In fact, they would be a terrible and very dangerous feature!


I like your take, though I think the analogy is more accurately applied as -- if you need lifejackets you are a bad sailor, or if you need a bicycle helmet you are a bad rider


Of course!

And if you happen to want lifejackets and seatbelts on your bicycle, then everybody will be safe to assume that you are an exceptionally bad rider.

Same thing for wanting types on languages where they are not needed.


Seatbelts don't impede my ability to drive (having to constantly manage the car keeps me in the seat). Types _do_ impede my ability to write code: I have to write more of it.

Types can certainly help prevent something from going wrong, but they're not a zero programmer time cost safety feature.

OP worded it aggressively, but if someone can't see how others benefit from lower overhead, they should look closer.


The whole derive arguments is a ease of access gimick, with a heavy payment later in the game.

This is why lua is in beginner sandboxes like robblox, which then will later turn into jaded developers, yearning for types.


Types are more like that annoying chime that beeps when you have the door open.


I think this is only true for a language like Python, or TypeScript, where types are second class citizens…

For me, using types in Swift is sort of like “NOS” in that it’s helped me go faster (and further”!


I still find typing in Python and TypeScript hugely beneficial, even just for how it makes my editor work better. Being able to click to a definition does wonders for reading unfamiliar code


definition

In python, go and C maybe, but in typescript? People tend to kungfu-type their APIs way too much where healthy repetition would suffice.

I believe ts typing power will eventually become “considered harmful”. I also think that ts should have a way to intertwine types as it does now, but leave that to technical part of dts and give a way to declare that by <that gibberish> you meant <this clear interface>.


Typescript types are really powerful imo. I didn't do much js but I was always amazed at how library authors can just "make everything click" with them.

Remind me a bit of Rust's type system.


> Maybe consider that you or other authors you’re working with are bad at writing software.

OK, I've considered it. Now what?

(I don't use typed programming languages, I just want to call out this kind of rhetoric.)


Yes! Totally agree.

Completely happy to accept that I'm a horrible developer. But that doesn't really solve any of my issues.

(I have absolutely no issues with Lua btw)


Like many Lua developers, I have an extended table library containing the following functions: `clone1`, which is a fast, jittable implementation of a shallow clone from the openResty fork, `clone(tab, depth)` which defaults to one and performs a shallow clone to `depth` which will unroll cycles, `cloneinstance` which recursively clones everything with cycle detection, but gives copies the same metatable as their original, and `deepclone`, which will also clone metatables. `clonearray` could exist but I haven't found a frequent need for it.

Hence the reason cloning is a library function rather than core: when you have only one data structure, there are a lot of ways to copy it, and that's before getting into the various ways that metamethods can override the default behaviors of a table. Do you want to clone every pair in the table, or do you want to clone only the ones returned by `pairs`, which has a metamethod which can override the default behavior?

There are a dozen decisions like this to make.


Congratulations! "syntax monocultures" is now a Googlewhack! https://www.google.com/search?q=%22syntax+monocultures%22


Hah! Thanks for that.


>Maybe consider that you or other authors you’re working with are bad at writing software.

You are making the classic mistake of thinking you aren't also just as bad as everyone else. Chances are you are just as bad or worse.

Taking advantage of tools that make mistakes less likely and accepting that you suck just as much as everyone else are requirements for being good at writing software I think (this applies to anything really).


Learning it recently for a small game design, I was surprised that you couldnt easily copy a table, and even more suprised you needed "metatables" to do it...the extra steps seem far from simple.

Maybe I'm just missing something. If I recall, I was simply trying to create a new 'object' (game character) from a template but it required metatable boiler plate that just made no sense to me.

Many languages, this is simply a = b, or at most allocating some space first.


>I was surprised that you couldn't easily copy a table

Lua's designers have a sort of maxim "if it can't be done perfectly, let the user roll their own". This can be frustrating, but for table-copying it's not surprising. Do you copy subtables by reference or value? What about recursive tables? Mutually recursive subtables? Closures in tables? And then userdata can contain references that are opaque to the language runtime. It's not easy to define the behavior of deep copy in the fully general case.


You might find it handy to add lua-enumerable.lua to your standard set of Lua-project modules:

https://github.com/mikelovesrobots/lua-enumerable/blob/maste...

See: table.dup()


NOTE: Doesn't copy metamethods, doesn't copy subtables either.


In many scripting languages this is not the case, and you are ever only passing around references. Python comes to mind.

Lots of people obviously have a problem with this as it deeply different from the algebra derived assignment syntax.

local a = b creates a local copy, but even then, its not a deepcopy, containing references to other tables.


python has both .copy() methods and a copy module. That's not to highlight Python's strengths, but an indication that it's a complex topic in Python - it has footguns here. The copy module might even do the wrong thing for a given object.


The algebra-derived assignment syntax kind of falls apart with mutation anyway.


Types are bicycles for the mouse.


The first paragraph in the introduction claims the "failure to fulfill expectations" of Algol 68 and Ada were because they were designed by a committee. Leaving aside whether they were or weren't disappointments, neither was really designed by a committee. Algol 68 was famously presented as a fait accompli to the IFIP committee by Adriaan van Wijngaarden, as documented by Dijkstra and leading to the minority report and ultimately Wirth's Algol W and then Pascal. Ada was largely designed by Jean Ichbiah, and all the various committees of the US DoD did were choose his design over the competitors.

Both languages strongly appealed to me, probably because of their cohesive (one-man!) designs, although I never got the chance to use them professionally. So I do agree that a strong, usually one-person, design is the way to go. But both Algol 68 and Ada failed for other reasons. I'm speculating, but I suspect they simply required too much of the average programmer: mathematical sophistication in the case of Algol 68, and discipline in the case of Ada.

The other plank of TFA's argument is that successful languages are built up slowly based on experience of requirements. I think if such a language ends up any good, it's either luck or someone spending a lot of effort pushing back on bad proposals. I'm sure you too have a list of languages in mind which grew in an undisciplined manner, until they strangled themselves. I think of language designers who allow that as like Maxwell Smart in Control headquarters, running coloured strands of wool between pushpins on a map until it's a woolly mess.

I suspect what really made Lua a success is it found users among game developers at the right time in its development, and did not try to be much more than that. In that sense, by listening to users and adding things, they achieved a good design (I assume – I don't really know the language), and because it did not achieve wild success that constituency of users was not so diverse as to baroquify the language.

A language can fail if it is a clean design but doesn't have users (Eiffel). A language with an ugly, committee, design can succeed if it has users (C++).


I was lurking in their mailing list for some time and they push back a lot, I’d even say they managed to create a culture of no-feature. Whether it was good or bad idk, because (as expected) some proposals sounded good to me, some so so. What makes Lua unpopular imo, beyond subjective trivialities, is that they break compatibility in every version and in fact they release flavors of the same core idea vs updates of a language. Also it is technical and not user-friendly for windows users, because luarocks (package manager) is unusable there unless you’re skilled in C build systems and are ready to fix these issues. I lost track of it at 5.3.

I think Lua would feel much better if it stopped at 5.2 (or even at 5.1, fixing the shortcomings in 5.1 way) and took care of what’s called ecosystem, emerging around its game popularity.


> Also it is technical and not user-friendly for windows users, because luarocks (package manager) is unusable there unless you’re skilled in C build systems and are ready to fix these issues.

I've found using hererocks[1] makes setting up lua and luarocks on Windows very easy. Running it in visual studio's command prompt has let me install pure Lua and C rocks.

However, I've noticed many rocks aren't updated on luarocks and the best way to install them is to point luarocks to the rockspec file in their git repo. Instead of `luarocks install testy` you do something like `luarocks install https://raw.githubusercontent.com/siffiejoe/lua-testy/master...` I don't use Lua for desktop development, so I only use rocks for dev tools to help write Lua for my embedded target, so I'm not sure how popular luarocks is these days.

[1] https://github.com/luarocks/hererocks


> in fact they release flavors of the same core idea vs updates of a language

What is the feature you're referring to here? If I read it correctly, it sounds more like JavaScript with their competing module/import schemes.


Tinkering with ways to do arrays, iteration, function environments, coroutines. Some ways are improvements, some may be seen as an improvement, some are just different.


I have used Ada during 8 years (3 years as student, 5 years work). The failure of Ada is the idea that "development of reusable libraries is left as an exercise for the developper". Standardisation of libraries was very slow and/or incomplete.


Honestly Lua is one of those languages that seems decently nice to use, fairly performant, and just makes me wonder why it hasn't been adopted for use more broadly in domains beyond just like being embedded in game engines. Am I missing something?


Lua just doesn't have the marketing other languages have. No big corporation behind it.

It does not have any exciting or frequent releases. It is basically done as a language since 5.1. New versions can be safely ignored, especially when you want to use LuaJit.

These days people simply expect lots of churn and frequent releases to keep the hype for a language up.

Also the current trend it towards static type checking which is especially hard to implement for Lua. There are some solutions for gradual typing but there is not exactly first-class support for that.

The small standard library might also have been a problem in the past but these days I would argue that JS has normalized that part quite a bit.


I’ve worked in a large Lua codebase, and its lack of any types gets very cumbersome. It is also non-trivial to get the full performance and by doing so lose some of the nicer features. For example, creating tables causes an allocation which is slow, so forget about using tables for vector types. These tables could have bad a metatype for operator overloading, but metatables cause multi-level lookups which is also slower.

I could use it for some light scripting, but definitely would not write whole projects in it.


> lack of any types gets very cumbersome

You might be interested in Teal ("the typescript for Lua") https://github.com/teal-language/tl


I find in super frustrating when a language doesn’t put a representative view of it’s syntax front and center in the README… (as a QuickStart or something)!


The tutorial they link in the intro is quite good:

https://github.com/teal-language/tl/blob/master/docs/tutoria...


Agreed! I just find it unusual that this isn’t “front and center” (as I said)


The nice thing about this particular case is that you can actually do something to fix this problem that is super frustrating for you!

You can send a PR!


At work, I use Lua (and LPEG) to process SIP messages for the Oligarchic Cell Phone Company, processing calls in real time, and only once in the seven years it's been running did I have to tune the code. It certainly works for us.


That’s great :) I do think it has its place.

We ran >200k lines of Lua for a 3d game at >60fps. We could not do allocations on the hotpath, or we would run out of our frame budget (which was around 1ms). Games are very hard to auto-test when not built with that in mind from the ground up, so any change to the code might unknowingly break any caller, and we would only know for sure once the game runs. Sadly the code base is 20 years old.


You mentioned in a sibling comment that this was using LuaJIT, do you know if it was before the allocation sinking optimization was added?

At some point (2.1?) LuaJIT added a peephole interpreter optimization which can follow a simple constructed table for awhile, and if it's never stored, the values it's conveying are just put on the stack.

I'm pretty fearless with creating transient tables, and run enough profiling to be moderately confident that the allocation sink is keeping that from providing memory pressure.

There's a larger thing here about the JIT being temperamental and having to kind of learn its moods, but: it's faster as an interpreter than other choices by a matter of multiples, and when the JIT works, it positively screams.


Honestly I am not sure. We were using the LuaJIT interpreter because JIT is not allowed on consoles or phones.


>For example, creating tables causes an allocation which is slow, so forget about using tables for vector types

I once added vector4 as a primitive type in my fork of Lua (to avoid allocations altogether) - it was surprisingly easy to add, took me a weekend.


We were using LuaJit which is a whole other beast.


Lua used to fill a niche very similar to Javascript: small lightweight OOP language that focuses on being embedded in a larger C program. Javascript won this war, mostly based on the explosion of the Web and the insane optimization work that was put on JS engines during the late 2000s.

JS ate Lua's cake, not on pure technical merits (the two languages are very similar) but because of their respective environments.


For reference JS isn't actually object oriented, it is a prototype language. You can fake it being OOP within that style, but it isn't really OOP, even if you can code in it that way.


If we want to be pedantic, prototypal inheritance is a kind of OOP[1]. What you're talking about is referred to as "classical OOP" (OOP using classes).

[1]: https://en.wikipedia.org/wiki/Prototype-based_programming


Just like Lua, hence their similarities.


That's fair. I didn't realize Lua was also a prototype language as I've barely looked at it. Been curious but it never fit my current set of curiosities.


> it hasn't been adopted for use more broadly in domains beyond just like being embedded in game engines

It might not be in your particular awareness bubble. Parts of the infrastructure that transmitted the request that allowed you to post your comment (the most prominent one is Nginx, but routers and switches with Lua-scripting do exist).

In my case, I work in Kong (which has a very healthy Lua plugin), I edit my code with Neovim (Lua is its main plugin-writing language). So I kind of "live and breathe" Lua. Still I am aware of other pieces of software that embed it that I don't use (Redis, Wireshark, even Wikipedia supports Lua on its templates).

One interesting characteristic of the language is that it is "barebones". It doesn't have features that are "built-in" in other languages. Things like parsing a json file or making an http request. As a result, the "host program" needs to provide those. Which ends up making "flavor Lua" - Lua with certain assumptions about the host. In this way, Lua is not "one big continuous landmass", but instead an "archipelago". This lack of central point makes it impossible to attach a "marketing/hype machine" to it. It's more like a silent revolution, the language stands on its own merits, for better or worse.


No batteries included. It's designed to be embedded as a scripting language, so its stdlib is tiny. People managed to write web frameworks in Lua, but it's hard to snowball a good package collection when you've got Python and node next door.


Lua and lualatex allow access to TeX internals and (relatively) easy programming of typeset documents: https://lwn.net/Articles/731581/.

Lua is the official language for writing Pandoc filters.

And, of course, NeoVim.

These are the contexts in which I use it; its embedding into TeX and Pandoc provides some powerful capability.


> Lua is the official language for writing Pandoc filters

Given pandoc is written in haskell.. an interesting choice. I guess investing in a DSL syntax was a cost too far.


No static typing, No ergonomic language features like lambdas, No functional programming, magic nil behaviour, global by default, no integer type (not sure if this was addressed), index tables instead of having a proper array/list type, missing switch, No assigning operators..the list goes on and on.

It was an average PL a decade ago and it is simply mediocre now. Only superb implementations like LuaJIT prop the language up.

I would prefer writing Enterprise Java (gasp) over writing Lua code for anything >5k lines. It's OK for small scripts but rapidly breaks down for anything larger. It's a bit funny that a complicated system PL like Rust is more comfortable to code than Lua.

Only using Lua personally nowadays due to Neovim and now that https://github.com/noib3/nvim-oxi has come out, I am going to use it even less.


> magic nil behaviour

What is magic in Lua nil? nil being false makes nil different from other non-boolean types, but it is both intuitive and convenient (I don't know a language where null/nil/undef are true in boolean context). What makes Lua a bit different from other script languages is that 0, "0", "", {} e. t. c. are not false in Lua. But it allows to avoid mess with truthy/falsy values we have in other script languages.


nil is like the absence of a value, reified into a value. Reading a variable that doesn't exist produces nil, and assigning nil deletes the variable.


Having a value that, when assigned to a variable or property, elides or deletes it is actually a desirable feature in MHO. Arguably, JavaScript's `undefined` should act like that, or nowadays more probably a well-known symbol. It's at any rate a nuisance that introducing one cavalier 'simplicity' (you can access `d.x` even when it does not exist, but you'll get `undefined` as value) causes so much accidental complexity (now you have to distinguish between so many fringe conditions (does `d` have a key `x`? does `d.x == undefined` mean `x` is set on `d`?). OTOH if you don't have a value that deletes a key from an object, then you'll have to special-case that operation because `delete d.x`, apart from being revolting syntactically, only exists as a syntactical construct.


Lua tables make no distinction between a table value being nil and the corresponding key not existing in the table necessitating hacks like: http://lua-users.org/wiki/StoringNilsInTables


Yeah, that's the point of nil. If you're trying to store it in a table, you're just fighting the language. Is there a good motivation for doing that?


I've done this on two rare occasions: round-tripping 'null' in JSON and 'NULL' in database queries.

My solution, which was perhaps overly cute, was a table canonically named No, which is callable such that No(nil), No(false), and No(No) all return true.

So I could say

   if No(value) then
When I needed to do conditional logic which excludes those reified null values, which isn't often.


> What makes Lua a bit different from other script languages is that 0, "0", "", {} e. t. c. are not false in Lua.

In Ruby only nil and false are falsey, everything else is truthy.


Same as Scheme.


nil is not fasley in Scheme. There is no falsey is sense that only #f is false :)


What do you mean by no lambdas exactly? Lua supports anonymous functions and they're in fact closures, since those functions capture variables from their outer scope.

I use functional programming extensively in Lua also. Could you elaborate on what it doesn't permit?

Integers were introduced in 5.3.

Assigning operators? It has metatables, you can absolutely implement your own operators.

If you want static typing you can use my IDE: https://github.com/Benjamin-Dobell/IntelliJ-Luanalysis/

Granted, my IDE is incredibly opinionated and not for everyone.

Also, Lua is not my favourite language to use, doesn't even make top 3. However, the robustness of its design, considering its simplicity, is incredibly elegant.


Ooh, didn't know about Luanalysis, thanks for creating it! Going to check that out.

I personally found functional programming non-ergonomic in Lua considering that anonymous functions are very verbose and there is no map/filter/etc in the standard language/library unlike just about every PL these days. You need to pull stuff in for basics and everyone does it slightly differently leading to non interoperability.

Sorry, I meant shorthand assignment operators. Those are quite convenient.


> Assigning operators

+=


Ah, thanks for the clarification. It does indeed lack those. I tend to call those short-hand operators since I guess technically `=` is an assigning operator.

Personally, I don't have a strong opinion on their omission, however I know some prefer the simplicity.


> now that https://github.com/noib3/nvim-oxi has come out, I am going to use it even less.

Woah, interesting ... provided there's success and uptake with this ... I'm imagining it could lead to a really slick and responsive editing experience that those of using (at least) slightly sluggish plugins might have been missing for a while now.


> No ergonomic language features like lambdas

x = function(a,b) return a+b end

x(4,5)

Is that not a lambda?


GP probably meant a short syntax for it, thus ergonomic. When you use lambdas a lot, this “function() end” part may become annoying.


There is Luau, however.

"Luau (lowercase u, /ˈlu.aʊ/) is a fast, small, safe, gradually typed embeddable scripting language derived from Lua."

https://luau-lang.org


Lua has had proper lexical closures and function expressions since 5.0 https://www.lua.org/manual/5.1/manual.html#2.5.9

It has had 64 bit integers since 5.3 https://www.lua.org/manual/5.3/manual.html#2.1


i dont know lambda was really easy to do it by onself.

filterdResult =

       lambda(Table,

        function(i)

          if i ~= 42 then return i; end

        end,
          setToFilterOut = {}
          function filterOutIfInSet(i, filterSet)


            if not filterSet[i] then return i; end

           end

        etc..
        )
Combined with properly, once defined decision sets this is really powerful. Almost of all my game decisions are lambdas mit once global defined decisionsets for unittypes. If i want to change something, for a unit, i only insert its type into the corresponding decision set and suddenly it has that property. Like dropping a smooth stone into a pond without ripples.

Its similar simple to the javascript implementations, once functions are firstclass members.

Functional programming would be harder. You need alot of meta table, result hashing for that a + b hash(a) + hash(+) + hash(b) -> Resultlookup. So its doable, by the law of look it up yourself, it has been done.


It is heavily used in some niche domains. Openresty comes to mind next to game dev.

OTOH, it is too close to C and not really a breakthrough language like Rust or Go. As far as style and brevity goes, Lua wins hands-down, but who cares?


It's also used as the main scripting language in NeoVim.

But if you want something more "out there", it's also the main language used to program open-source radio control remote (openTX) for drones/planes/gliders: https://medium.com/rc-soaring-digest/ive-got-the-power-opent... https://github.com/jfrickmann/SoarOTX


1. Each minor version of the language is distinct enough to be incompatible with the previous version. A project embeds one specific version of Lua and never upgrades it.

2. Since it is embedded, it has a pretty small standard library that the embedder can remove or extend.

Both lead to Lua communities being more about individual projects which embed it.


A good example of this is the Max/MSP audiovisual environment, which, amongst other things, has both Lua 5.1 and an ancient JavaScript engine (JaegerMonkey from Firefox 4) embedded in it to this day.


Lua has been designed as an embeddable scripting language and it is used as such in various domains and programs. It's not really suited for developing large applications, though.


You can write largish standalone application in Lua and it is not always a poor choice - Prosody [1] first comes to mind. But qualities which make it a good embedded language make it less _attractive_ for other uses.

Lua has very simple syntax and small stdlib which allows its implementation to be very small - you can add Lua to your application and not increase its size significantly. But when the size is not a concern most programmers prefer languages with rich, powerful syntax lots of features and batteries-included stdlib (which is completely opposite of Lua).

[1] https://prosody.im/


Some games use it for a UI/scripting layer but it's a nightmare to work with for anything complicated.


Index by 1


This was such a weird decision. Lua is meant to be embedded, meaning it will have to call application code where indexes start at 0. Why make the Lua indexes not match?


Some big influences on the syntax are Modula and Fortran. The first allows you to start an array with any index you like, the second starts it with one. As the article says, it started as a data language for engineers who may have been familiar with Fortran. The C-like languages were not as overwhelmingly common back when Lua started, as well.


> When we started Lua, the world was different, not everything was C-like. Java and JavaScript did not exist, Python was in an infancy and had a lower than 1.0 version. So there was not this thing when all the languages are supposed to be C-like. C was just one of many syntaxes around.

> And the arrays were exactly the same. It’s very funny that most people don’t realize that. There are good things about zero-based arrays as well as one-based arrays.

> The fact is that most popular languages today are zero-based because of C. They were kind of inspired by C. And the funny thing is that C doesn’t have indexing. So you can’t say that C indexes arrays from zero, because there is no indexing operation. C has pointer arithmetic, so zero in C is not an index, it’s an offset. And as an offset, it must be a zero — not because it has better mathematical properties or because it’s more natural, whatever.

> And all those languages that copied C, they do have indexes and don’t have pointer arithmetic. Java, JavaScript, etc., etc. — none of them have pointer arithmetic. So they just copied the zero, but it’s a completely different operation. They put zero for no reason at all — it’s like a cargo cult.

https://habr.com/en/company/vk/blog/459466/


This. I was doing Ethernet packet assembly/disassembly with one part in C, the other in Lua.. Let's just say that I'm not a Lua fan to say the least.


I was compiling a game which needed Lua. Lua used its own make system without config files which failed with an obscure error message. Since then i avoid it.


I really wish LuaJIT was the standard for Lua. Lua with a C FFI makes it so much easier to work with C libraries like SDL, as opposed to writing Lua bindings from within C. Lua alone is great, but being able to write C structs in Lua and overload operators is chef's kiss. Of course you can ignore this opinion if you're one of those people who believe C is an abomination to God whose blight should be stricken from the world. To each their own, but for me, Lua is the best C framework out there.

Lua is also my go to suggestion whenever threads about which language to use for configuration come up. The syntax of lua tables are basically JSON, except without quoting keys and with comments. And the overhead of embedding it is likely close to nil compared to the interpreter for YAML or whatever.

It's a nice language. Wish I had something more profound and complex to say about it. I would just suggest considering JuaJIT if you ever do need to work with C and it's allowed. Or just Lua if you're a masochist and want to deal with the stack.


> I really wish LuaJIT was the standard for Lua. Lua with a C FFI makes it so much easier to work with C libraries like SDL, as opposed to writing Lua bindings from within C. Lua alone is great, but being able to write C structs in Lua and overload operators is chef's kiss. Of course you can ignore this opinion if you're one of those people who believe C is an abomination to God whose blight should be stricken from the world. To each their own, but for me, Lua is the best C framework out there.

Honestly, I keep finding LuaJIT's FFI to be profoundly disappointing. It falls into the common FFI trap of support, essentially, a C ABI—sure, it parses C declarations, but without preprocessor support and no good way to ask for, say, "just get me all the declarations from errno.h", it cannot work with the universe of code that expects you to pass in e.g. symbolic constants provided in a C header, or preallocated structs, or via preprocessor macros, that maintains compatibility only at the C source level.

It's not an easy problem, to be sure, short of doing the C++ thing and embedding most of C outright.


Yep, pretty much.

I wound up writing a thing for this years ago that worked pretty well for the use cases I had at the time, but it was pretty complicated (implementation wise) and had some potential conflicts with other FFI-written stuff that imported "almost but not quite correct" stdlib definitions - since my thing would always import the exact definitions from the system header files.

Still, it was fun and I thought it worked reasonably well for what it was.

https://github.com/bdowning/lj-cdefdb


Yes, it's not perfect, but I think it's better than Lua on its own (assuming you don't need anything newer than 5.1)


Have you tried hooking up the C functionality with "sol2" and regular Lua?

I have been prototyping with it the past couple of weeks, and it took just an hour to wrap all of the glm matrix and vector types, including overloaded operators to do fully transparent vector and matrix algebra in Lua, including passing of values to and from the outside world. I was really impressed by how straightforward and simple it was.


I wasn't aware of it but I'll check it out.


We were very pleased that Roberto Ierusalimschy came to DConf last week and gave a great talk on Lua!

https://dconf.org/2022/index.html#robertoi

https://www.youtube.com/watch?v=04gJXpJ1i8M&t=1711s


Wow, I just watched the video and was surprised and delighted to see Roberto talk about Pallene (typed & compiled sister language for Lua). Fantastic!


I recently learned lua and wrote an alternative to bat that outperforms it by an order of magnitude. I thought Rust was supposed to be fast! :)

https://jeskin.net/blog/clp/

Love the language!


Lua is my tool of choice for code generators in C projects. Not the intended use case for the language but it's very good at it, and a single file lua.c built along with the rest of the project is no bother.


I did that too.. so fast to setup some definition generators, its really lovely.


I've worked now for 3 years on a large lua game code base, over 4000 files, 1.5 million lines of code.

In the first week or so, I was a bit weirded out by the lack of language features, as I come from C#/Typescript/C++, but I was very surprised that after 2 or 3 weeks, I was already doing very complex tasks on the code base.

I think a lot of that comes from the simplicity of the language. It's very difficult to surprise you, everything works in pretty much the same way.

Here are some things that I will miss once I move to other languages: (note that most of these are not things that come from simply using lua, you have to implement it into your framework/engine, but they are still pretty common)

- stack traces print the contents of the variables in the stack. Not all lua code bases have this, but it is easy to implement.

- if the code crashes, you can fix the code and continue. This doesn't always work, and requires the code base to be written in a way that supports it, but it is definitely possible and I've used it many times.

- debugging works really well. You can easily attach and inject code, stop on exception and inspect the state.

- settings are also lua code. This is probably the biggest thing I'll miss. I love being able to have simple functions as part of settings (e.g. things like tweening functions), being able to generate settings based on other settings, or run simple sanity checks, all on the same file.

- index starting on 1, this is definitely an unpopular opinion, but IMO it just makes things so much easier. When you need to access the last element, you just do tbl[tbl_length], no need to decrease by 1, or doing a for loop, you only specify the indices you're actually accessing "for i = 1, last_index do end". I think it really helps with off by 1 errors. I used "normal" indices for over 10 years before this project, and I would still occasionally have these errors, but with lua, I don't really remember having them.

- not having to fight the compiler to quickly try out different things. Need something from a completely different system? Just add it to the global table and access it from the other place.

A big learning I got from transitioning from languages with a very strong type system to a dynamic language like lua, is that in order to be effective, you really need to use code architecture patterns, otherwise things become very hard to reason with. This might be counter intuitive, but I think you need to be a better programmer to use lua effectively, than you need to with a language like C# or Typescript. With the latter languages, the compiler helps you a lot, but with lua, you have to know how to use these things on your own, because you can pretty much do anything and that can be reeeeally bad :)


I love to see the Lua love on HN, especially given my other languages of choice are generally disliked around here.

Funny enough, I was just mentioning to a friend this weekend that I would love to write Lua as a full time job (and particularly in gaming), but those jobs seem nearly non-existent.

How do you recommend going about finding opportunities like yours?


If you want to work on "AAA" games, I don't think there are many companies left using it to this scale. An engine where those kind of games are developed almost fully in Lua, AFAIK, is Bitsquid (later Stingray by autodesk), but that has been discontinued. There are still some companies that use Bitsquid derivatives though, like Fatshark, Toadman and Arrowhead. See https://en.wikipedia.org/wiki/Bitsquid

As for non "AAA", I think https://love2d.org/ is quite popular for game jams and commercial 2d games - I haven't used myself though.

So maybe look for opportunities in companies using those engines.


I worked for a few years on a project developing a content using openresty, if you're interested in other Lua uses/jobs.


> a large lua game code base, over 4000 files, 1.5 million lines of code

Interesting; how do you manage to keep consistency? Do you have special tools to e.g. detect inadvertent global variables? I once wrote a Smalltalk VM in Lua (https://github.com/rochus-keller/Smalltalk/blob/master/Inter...) which is a much smaller code base, but even with this modest size I quickly would have lost track of e.g. scopes and names without tools I had to write myself (https://github.com/rochus-keller/LJTools).


Most of the time nothing is used. The thing is that iterating is so quick, that you find the problems really fast.

Although, I've been using luacheck https://github.com/mpeterv/luacheck. It is quite nice, but you have to write down the global variables by hand on the config file.

Edit: Also, the vscode lua plugins have been getting quite good, and completion works to a certain extent.


It depends. You can also configure luacheck from within the file you are checking. For instance, in some of my lua code [1], I have:

    -- luacheck: globals init handler
    -- luacheck: ignore 611
The first line tells luacheck that the variables `init` and `handler` are globals, and the second line tells it to ignore lines that contain just whitespace (a quirk the text editor I use uses to manage indenting levels).

[1] https://github.com/spc476/port70/blob/master/port70/handlers...


Lua’s language server can be nice for detecting unwanted globals. It gives you a warning whenever you declare a global that starts in lowercase, which works nicely if you’re okay with using uppercase globals as a convention


> I think you need to be a better programmer to use lua effectively ... with lua, you have to know how to use these things on your own, because you can pretty much do anything and that can be reeeeally bad :)

I find this sentiment interesting. Perhaps somewhat akin to Linus Torvalds famously preferring C to weed out bad programmers.

I think many people would say that a language which makes it easier to do things poorly is objectively worse than the alternative. But the way a language "selects" the sort of programmers that use it is an important second-order effect (maybe even more important than the initial one?).


> index starting on 1, this is definitely an unpopular opinion, but IMO it just makes things so much easier.

Not modulo!


At work we make plentiful use of Lua on our telephony backend. As part of many dial plans we need to invoke certain "scripty" functionality - stuff that runs top to bottom to do one thing and then return - which may require e.g. database access, RabbitMQ interaction, Memcached key wrangling etc., and Lua's fast start-up and executional speed facilitates this for us on large scale better than almost anything else.

We initially began with Python for some of these things, which quickly became an untenable and elaborately consummated performance disaster. There are plenty of techniques to get around its slow start-up and performance issues, but they come with a slew of new complications compared to the simplicity and ability to quickly deploy/update/execute from local file system.

Lua for us makes the difference of being able to, on one and the same piece of hardware, manage a thousand simultaneous phone calls instead of just a few hundred.


Why only the history until 2001? What about the years since then?


In 2001, we didn’t yet have the advantage of knowing what the next twenty years would look like.


The article was written in 2001.


Very interesting, the authors find Tcl syntax highly cryptic.


No mention of LuaJIT


Presumably because this document was written four years before LuaJIT was developed.


And LuaJIT is from another author, Mike Pall from Germany (Lua itself is from Brazil).


Apart from c, lua is my favourite language. c + lua is the perfect combination and I have developed a lua-based build system using them. https://github.com/xmake-io/xmake


[flagged]


Yeah my experience as well. I've worked in lua for years and nearly every codebase has a home grown, often incomplete or fairly bad implementation of a json parser, csv writer, rgb converter, templating engine, etc. Only old-school php rivals it in this.

And for some reason this language seems to provoke people into writing custom build systems. A huge number of lua projects have them. In practice make can be pretty bad too but at least it's bad in familiar ways.


Lua itself is _really_ good as a build system. Spawn a process with libuv, wrap it in a coroutine to periodically check on progress, done.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: