
Tables - tosh
https://www.lua.org/pil/2.5.html
======
lxe
In 2010 I worked on building a "dynamic" web app that would run on a very tiny
embedded device -- no MMU, about 130 bogoMIPS. Think of an old wireless router
you have at your parents' place.

There aren't that many options for building a "modern" web backend on
something like this -- the most popular being C compiled into executable(s)
served via thttpd and CGI.

Things like templating, or JSON parsing for that matter, would be much easier
in something higher level than C, but python, PHP, node, etc are simply too
huge and slow.

I discovered Lua, and it fit the niche exceptionally well. The syntax and the
data structures takes a while to get used to, but once you do, they feel
rather powerful, especially for such a lean interpreter. It compiles into
something like a 120k statically linked executable and is (relatively)
phenomenally fast -- not only for the tiny computer on which I had to run it,
but also for me, who had to write a complicated web app using it. I almost
felt like a demoscene developer -- I was able to run something that would
otherwise require a full featured machine on a tiny embedded board. Even to
this day, LuaJIT, OpenResty, Lapis remain up there on the benchmark tables
when it comes to web apps.

~~~
slezyr
You can run PHP on router with 3Mb of storage and 64Mb of ram.
[http://ph7.symisc.net/](http://ph7.symisc.net/)

DIR-320 Used php for it's GUI.

~~~
seppel
Back in 1998, Apache, PHP, Mysql and Netscape 4 did fit into 16 MB of RAM :)

------
leggomylibro
One thing that I like about Lua over Javascript is how self-documenting, fun
to write, and easy to read it is. It has a very simple syntax, but the
extensibility of its core structures (like tables) let you accomplish a lot
with that simplicity.

Its 3rd-party libraries also tend to be closer to C/C++'s "drop-in" solutions
like STB[1] than the enormous JS ecosystem which often requires extra tools
like Node and/or extra packages like JQuery.

Admittedly, Lua's ecosystem is much smaller than Javascript's, but in my
experience Lua is vastly easier to maintain. You can certainly write bad Lua,
but it's one of the only languages where I don't implicitly dread reading
other people's code.

It is sort of annoying that tables which are treated like arrays are 1-indexed
by convention, though.

[1]: [https://github.com/nothings/stb](https://github.com/nothings/stb)

~~~
chrisco255
Does C/C++'s STB or Lua's 3rd party libs cover cross-browser quirks and http
methods like JQuery does? It sounds like Lua/C and JavaScript are used for
totally different things. And Node isn't an "extra tool" it's a server. No
doubt JS projects sometimes come loaded with excessive dependencies but
Node/JQuery are bad examples and not equivalent by any stretch to STB.

~~~
leggomylibro
Nope; Lua is not a good choice for a website's frontend.

But people use Javascript for a lot more than just websites, and I've lost
count of how many times I've been frustrated that a JS library is distributed
exclusively through package managers like NPM even when the library is not
specific to a browser.

~~~
paulddraper
NPM isn't specific to a browser.

~~~
shawnz
Is NPM even usable from the browser in any capacity? I would argue that it's
specific to everything except browsers!

~~~
s_ngularity
NPM is definitely usable as a package manager for frontend Javascript
applications, just needs a little more complicated webpack or similar setup
than a node.js app.

------
anonytrary
Lua's feature set is tiny, and that's precisely what I love about it. Ruby
feels a lot like Lua, but I vastly prefer Lua to even Ruby, because of how
minimal it is. As someone who writes ES6 on a daily basis, I feel that Lua's
syntax explains itself -- you can start writing Lua code in 30 minutes. People
have always said that Python is fun to write, but I've never felt that about
Python. On the other hand, I can definitely say that Lua is pleasing to write
in. Python, to me, has always felt like a chore compared to Lua.

~~~
abecedarius
Funny, it's Lua that feels like a chore to me, because most things take around
twice as many lines of code than in Python. (Though some of those lines are
just 'end'.) I want to like Lua more because it's so much simpler and faster,
but it could've come closer in expressiveness and catching errors.

~~~
legends2k
Same is true for me too; lack of batteries (std lib) isn't helping either.

------
oweiler
Started coding in Lua 2 months ago and instantly fell in love.

Higher order functions, coroutines, the ability to return multiple values from
a function, no coercion on comparison operators make coding in Lua a breeze.

You can learn most of the language within a day.

Ofc not everything is perfect: The package ecosystem is growing but still
small compared to other languages. Anonymous function definitions are pretty
noisy.

Still I think it's one of the best designed languages you can find.

~~~
sdegutis
Lua is amazing in that it is very small, portable, and easily embeddable. But
aside from those three things, Lua is semantically almost identical to modern
JavaScript.

I've embedded both and used them heavily in my various window managers, and
these days I personally recommend embedding JavaScript over Lua if possible.

But when a small, portable and lightweight language is needed, there's also
Sparkling[1], which is like the best ideas of JavaScript with the minimal
footprint and portability of Lua.

[1]: [http://h2co3.github.io/sparkling/](http://h2co3.github.io/sparkling/)

~~~
vmsp
What JavaScript interpreter do you use for embedding? I know of MuJS [1] but
it only supports ES5.

[1] [https://mujs.com/](https://mujs.com/)

~~~
sdegutis
My JS-embedded apps only target macOS so I use Apple's builtin JavaScriptCore
framework.

~~~
nikki93
In my experience LuaJIT in interpreter only mode has better performance than
using JSC (you can’t use JIT in JSC either — only WKWebViews can JIT).

(edit: sorry this is regarding iOS)

~~~
sdegutis
Maybe, but my use-cases (window manager and other automation stuff) don't
really have a strong need for speed or high performance. Mostly it just sits
there idle 99% of the time and runs callbacks quicker than the UI that it
manipulates is visibly updated.

~~~
nikki93
Yeah I think it does end up boiling down a lot to use cases because the big
differences b/w Lua and JS are in availability of libs / integration and perf.
In my case I do a lot of 2d graphics where love2d.org is available and perf is
important. :) C interop is also really important, and LuaJIT C FFI is waaaaay
nicer to use than JSC C API.

I’ve ended up doing a lot of JS with React Native for “app-y” mobile apps
though.

~~~
sdegutis
If perf is important, I'm surprised you're using Love2d and not just using C++
with SDL and Box2d directly. Afaik Love2d just uses vanilla Lua (and not
LuaJIT) which, while faster than similar languages, is still pretty wasteful
of cycles when high perf is needed.

~~~
armitron
Love2d can use luajit or plain lua.

------
scythe
Lua is a pleasing language to work with, but only that, unfortunately. It has
never caught on in desktop apps due to a lack of suitable GUI library
bindings. It never caught on in web apps thanks to a lack of suitable web
frameworks.

There are at least a dozen half-implemented or abandoned Lua GUI projects,
including at least three Lua-to-Qt binding toolkits and one briefly maintained
by PUC-Rio (where Lua originates). But the other day I wanted to write a
simple GUI to support formatting documents with a certain LaTeX template, and
I struggled to find one that could guarantee that my users would be able to
run the software on their various OS platforms. There are even more half-
working Lua web frameworks, including Lapis, Ophal, Orbit, Sailor, and Tir,
three of which have had brief moments in the limelight as the "preferred" Lua
framework. There are at least three projects that attempted to add types to
Lua, and no less than six parallelism libraries.

If you view it as a competitor to Python, Lua is a case study in open-source
community mismanagement. There are five projects that attempt to solve every
outstanding problem usually none of which has more than three regular
contributors. There are many competing "Lua standard libraries", and after the
falling out between Mike Pall and PUC and the controversial introduction of
integers, there are four similar but distinct versions of the Lua language in
common use: Lua 5.1, Lua 5.2, Lua 5.3, and LuaJIT 2.

But if you view it as a research project, Lua has been incredibly fruitful and
continues to be. Any organization with the critical mass required to maintain
their own internal ecosystem can use Lua without ever noticing the disarray in
the wider community, and many do. It's just... annoying... from the
perspective of the US/European open-source crowd.

~~~
andrewmcwatters
Perhaps I'm uninformed, but I was always under the impression there were two
camps:

Lua 5.1.5/LuaJIT users, and Lua 5.2+ users. Game developers, performance-
sensitive developers, FFI users all tend to use the former, and when not
necessary, I've seen people use the newer versions.

Is there more segmentation between 5.2 and 5.3 than I'm aware of?

------
andrewmcwatters
I love that Lua uses one-based numbering, if only to point out undesirable
developers who don't understand the difference between offset and count.

You don't work with pointer arithmetic directly in Lua syntax, so why would
you need offsets?

Complaints about ~= as the negation of equality are as petty as well. The
syntax in question isn't _just_ used by Lua, either, and it usually tells me
that a developer can't respect differences between languages.

~~~
Pimpus
> The syntax in question isn't just used by Lua, either, and it usually tells
> me that a developer can't respect differences between languages.

Actually, the two examples you bring up are paragons of asinine design. I
can't imagine it being easy to justify such design decisions, your attempt to
do so was wholly unconvincing.

~~~
andrewmcwatters
That "asinine design" comes from decades old syntax practices like ALGOL, Ada,
and MatLab.

Perhaps exposing yourself to other languages might inform your responses on
debatably the largest technical forum in the industry: one with many
developers from widely varying backgrounds.

~~~
Pimpus
Heh, you don't even try to justify it, just point out prior art in some
irrelevant "languages". Yeah, definitely not easy to defend such choices. Even
the fact that this turns off potential Lua programmers such as myself makes it
do more harm than any potential good (and I am hard pressed to find a single
good thing about these asinine choices).

~~~
andrewmcwatters
In mathematics, there are multiple symbols for negation.
[https://en.wikipedia.org/wiki/List_of_logic_symbols](https://en.wikipedia.org/wiki/List_of_logic_symbols)

What is there to defend? Can you explain why it's "asinine design?" You don't
actually elaborate as to why, and I've provided you both academic background
in mathematics and prior art. I apologize if I've missed your point.

~~~
Pimpus
The fact that this discussion ALWAYS comes up when talking about Lua, with
people saying they won't even try the language, should clue you in how
terrible these design decisions are.

~~~
andrewmcwatters
You're right: This discussion always comes up with developers who constantly
have petty complaints.

~~~
Pimpus
I would venture to say that you're just out of touch.

------
sdegutis
Lua tables are semantically almost identical to JavaScript objects. The one
key difference is that any object can be a key in a Lua table, whereas all JS
object keys are coerced into strings. The other more minor difference is that
you use getmetatable() and setmetatable() instead of modifying or setting
object.__proto__

~~~
oihoaihsfoiahsf
They're identical to dictionaries/hash tables in pretty much any language,
unless I'm missing something. Besides C, every language I've worked in comes
with one of these things built-in. It's surprising to me that so many people
consider this noteworthy today. Would someone please enlighten me as to why it
is?

~~~
nikki93
Because `.foo` means `[‘foo’]` and because you can easily make sequences out
of them (if you write `{ ... i1 = v1, v2, ... }` then `v2` automatically gets
the “next” natural number as a key) the ergonomics make them usable as
structures and arrays easily. Also the ‘:foo()` syntax binds the LHS of the
operator as the first parameter for a method call, and metamethods allow you
to easily implement inheritance / dispatch / etc.

It’s more about ergonomics than availability.

~~~
thanatropism
Not a full equivalence, but this[0] gets you x.foo, x.bar ergonomics as
opposed to x['foo'] etc.

[0]
[https://docs.python.org/3/library/types.html#types.SimpleNam...](https://docs.python.org/3/library/types.html#types.SimpleNamespace)

------
jdonaldson
Tables and metatables are incredibly flexible constructs in Lua. I was able to
support nearly all the Haxe language constructs for Lua with little more than
tables, floats, and strings.

[https://haxe.org/blog/hello-lua/](https://haxe.org/blog/hello-lua/)

------
dkrikun
Have been using Lua 5.3 and luajit for a few years. Also have bought the lua
book for 5.3. My thoughts:

\-- really sweet consistent and simple language

\-- weak, fragmented ecosystem

\-- easily embeddable yet powerful

\-- few bad decisions: arrays as tables, coercions, 1-based arrays, no gradual
typing

~~~
stcredzero
Gradual typing can be very useful. Coercions, like any implicit
casting/conversion can have problems. 1 based arrays are a pain. On this much,
I'd agree.

Why are arrays as tables a problem? Is it a matter of efficiency, or is it a
type safety issue?

------
varunramesh
Lua is an awesome language, but there are significant gotchas, especially with
regards to the behavior of ipairs and the length operator -
[https://blog.varunramesh.net/posts/lua-gotchas/#the-
behavior...](https://blog.varunramesh.net/posts/lua-gotchas/#the-behavior-of)

------
dividuum
My favorite part of Lua tables is the syntax feature that makes it possible to
use a single table argument when calling a function like this:

    
    
      some_func{
         key = value;
         another_key = another_func{
             foo = "bar";
         }
       }
    

Note the use of { and } instead of ( and ). This almost makes it possible to
build a DSL. Oh. And the __mode option in metatables to create weak tables by
key/value.

------
i_feel_great
"A Lua configuration file is also code" is what won me over initially.

[https://www.lua.org/pil/10.1.html](https://www.lua.org/pil/10.1.html)

~~~
shawnz
This is a major antipattern IMO since it makes it very difficult to
programatically change configuration files. Unfortunately it seems to be all
the rage these days to make a DSL for your config files.

~~~
corysama
I don't understand. Lua config is just Lua data structures. Load Lua data
structures, modify them directly because they are the language's native data
types, serialize them back to text. How much easier do you want it?

~~~
shawnz
What if the file doesn't just contain literal values in the data structure?

~~~
corysama
Then yer shooting yer own foot. Don’t put functions or expressions in your
“Lua-SON” any more than you would in your JSON.

I guess if you lack confidence in your coworkers’ ability to resist
temptation, you could write a checker using Metalua. That would make a good
git submit hook.

Doing it “wrong” was one of my fav dev tales. I wrote a custom UI system in
OpenGL for an iPhone 1 game (memory budget 32mb). Didn’t have time budget to
make a visual editor, so I made up a Py-SON notation that simply loaded as
Python. From there I used CTypes to convert the Python data tree into binary
files full of arrays of C structs. Loading that in C was just fread(), cast a
pointer.

The big win came when we realized we had way too much UI to create and not
enough artist time to create it. So, another programmer and I sat down and
wrote a suite of Python functions that made generating UI components much
easier. It required a programmer-artist pair to use. But, otherwise it would
have simply been impossible to complete on time.

------
oldandtired
I have been using tables in Icon since 1986 (they were in Icon before that).
Tables allow key/value pairs to be anything. You can set up a specific value
to be returned if the key presented to the table doesn't exist. Lists, sets,
tables, records are the mutable values, strings, csets, integers, reals are
the immutable.

Failure is an option, so all expressions can succeed and return a value or
fail with no result. So there is not an issue with the truthiness of values
and the semantics of true/false.

Simple tests like

if a < b < c < d then { do something } else { do something }

are standard in the Unicon/Icon languages.

Icon was my goto language until about 2000 or so and thereafter I have been
using Unicon (the Unified Extended Dialect of Icon).

1 based indexing is very useful when you have the dual of indexes < 1 starting
at the right hand end of any string or list. Hence, you can work from either
end if you need and there are good use cases for starting from the RHS of
strings and lists.

I have looked at Lua in the past and nothing in it has given me any incentive
to move away from Unicon/Icon. Lisp/Scheme/Kernel and FORTH/Factor have more
notable (as far as I am concerned) facilities than Lua.

Though Unicon/Icon has flaws and certain kinds of missing facilities like
lambda's, I find that I am more productive in Unicon/Icon than I have been in
other languages. YMMV.

------
coleifer
Love lua. Luajit is stupid fast and the ffi stuff makes it a snap to integrate
with other libraries. You can find Lua in neat places like nginx, redis,
tokyotyrant...

I dislike the direction python has been going (twisted...i mean asyncio, type
annotations, f strings). Lua is like a breath of fresh air.

Downsides are small standard library and 1-based indexing _shudder_.

------
singularity2001
lua could be really nice if they fixed these:

indexing starts at 1 but a[0]=1 does SOMETHING

\-- // # stupid -- comments! / __/

0 is truthy # I just love the simple logical mathematical python way
(0=ø=()=[]={}=false)

if undefined … -- treated as nil

function pseudoclass:new …

But by far the biggest complain is the packaging. luarocks SUCKS more than
almost anything, at least for me.

luarocks install torch Error: Your user does not have write permissions sudo
luarocks install torch Error: No results matching query were found. and on and
on and on (non-representative excerpt of my pains)

~~~
andrewmcwatters
> 0 is truthy

Nope. 0 being falsy only makes sense in pointer-oriented languages where NULL
is a null pointer at address 0. In Lua, 0 is a number. It's not a pointer
address.

Which leads to:

> a={1} a[0]==nil a[1]==1 indexing starts at 1 but a[0]=1 does SOMETHING

So does -1: should -1 be falsy, too?

> if undefined … -- treated as nil

Pardon? It is. Are you asking for an undefined keyword? Why? In the Lua C API,
you already get `lua_isnoneornil` to begin with.

> function pseudoclass:new …

Lua is a prototypal language.

> but by far the biggest complain is the packaging.

You know, thank God. Because JavaScript is probably the closest thing to Lua
and look how that turned out.

The only thing holding it back is that the community doesn't need or want it.
It's also small enough that perhaps no one has made a good package manager for
Lua yet. But the `package` module in Lua already provides search paths, so
it's fairly low effort. Frankly, I've never had a need for it. I don't want
npm for Lua.

------
ubertaco
Does there exist something along the lines of Typescript for Lua that adds
optional type annotations and static analysis?

~~~
andrewmcwatters
[https://github.com/titan-lang](https://github.com/titan-lang)

~~~
ufo
I think the closest analogy would be Typed Lua. Titan is a bit of a different
approach (simpler type system, more focus on performance)

------
Grue3
>can be indexed not only with numbers, but also with strings or any other
value of the language, except nil.

What could possibly be a reason for not allowing nil?

------
funnotatparties
the standard PHP array everyone

its really an amazing object type, especially when you are given a great api
to manipulate it. Which PHP does have.

~~~
sdegutis
Lua predates PHP by 2 years, and I'm sure this combination of arrays and hash-
maps predates both languages.

Either way, I'm not sold on it. Arrays and hash-maps are fundamentally
different, not only for optimization's sake[1] but even in how people use
them.

[1]: Recent versions of Lua now try to detect whether a table is an array, and
apply optimizations when all its keys are ordered numbers without holes.

~~~
wahern
Lua doesn't try to detect whether a table is an array. The way it works is
that a table is internally composed of two data structures, a hash part and an
array part. Normally, integer keys go to the array part and everything else to
the hash part. However, integer keys of a certain size will overflow into the
hash part so that, e.g., storing a single integer key of 2^32 doesn't allocate
an enormous empty array part.

In this way Lua already optimizes the array use case naturally. It never tries
to infer whether a table is supposed to have array semantics or hash
semantics. You can use a table as a hash, as an array, or (commonly) as both.

The cost of this simplicity and concision is born by the semantics of the
length operator (#). The default __len metamethod on a table does a binary
search looking for the first missing positive integer key, the boundary that
marks the end of a logical array. The binary search will work even if your
integer keys have spilled over into the hash part, though it works much faster
if it doesn't have to inspect the hash part.

This why in Lua your arrays can't have holes (non-sequential positive integer
keys), at least not if you want #t to behave as expected. Lua has no way of
knowing the size of your array otherwise, at least not for plain tables
lacking user-defined metamethods.

That said, there's a convention that uses the string key "n" to record the
intended length. For example, table.pack() assigns the argument list to a
table and sets "n" to the number of arguments. It does this because a nil
argument value would create a hole. Also, since Lua 5.3 you can overload the
__len metamethod, which could simply return t.n. Similarly, you can overload
the __index and __newindex metamethods so that insertions update t.n or some
other marker.

FWIW, I've tried hard not to express any value judgments in the above
description. I've also deliberately abstained from discussing array-related
language proposals.

~~~
Dylan16807
I would argue that the length semantics are mostly unrelated to the hybrid
array/hash nature. You could have the same problems on an array-only data
structure, and you can invent semantics that avoid them without significantly
changing the data structure.

------
Jyaif
The one-index is as idiotic as ever, especially for a language that is
supposed to interact with other languages.

~~~
dang
Please follow the site guidelines when commenting here.

