8 ms·
I'm wrapping up a multi-year personal project, a game written fully in lua using love2d. To me, the beauty of lua is the simplicity and lack of learning curve:
by nequals30 2y ago
I'm wrapping up a multi-year personal project, a game written fully in lua using love2d.
To me, the beauty of lua is the simplicity and lack of learning curve: I can usually accomplish whatever I need to without looking anything up (as the author said, everything is a table so there isn't much to overthink). Also, the community and support around love2d is fantastic.
One thing that's bothered me is that lua silently returns nil when you reference non-existing elements. That's been a pain when debugging, since a line with a typo (`a = typo`) doesn't fail, and the code fails much farther downstream (e.g. when doing arithmetic on `a`). So almost all my errors end up being "trying to do operation on a nil value", and there is no indication of why it's nil.
- wwwigham 2y agoYou can define a metatable on your objects of interest (or the root table meta table if you don't mind breaking the language's conventions and thus libraries) with __index and __newindex members. Then you can throw in those by calling the `error` function when they'd otherwise normally return nil, should you desire it. But runtime checks have a cost, and static types that transpile away are a bit better for overhead so long as you don't mind the build step, so using one of the typed lua variants is probably a bit nicer in the long term. Catching those typos early is their bread and butter.
- dividuum 2y agoI think you can add a metatable to _G with an __index function. This should be called when accessing undefined local variables (as they end up trying to access the global scope _G) and you can thrown an error.
- deleted 2y ago[deleted]
- edflsafoiewq 2y agoA linter like luacheck is better for accidental globals, but I think the GP was talking about doing a = someTable.typoedFieldName.
- darknavi 2y agoYou can. In our game engine ~10 years ago we would hook the global table to stop designers from creating globals (the default in Lua without using the local keyword) at certain areas in the game frame, mostly to stop this exact trap. I toyed with the idea of inverting the semantics of global and local in lua and to remove "local" and instead default to local and have a "global" keyword. Looking at lua.c quickly dissuaded me when I was a much more junior programmer, but now days it might be fun to try.
- QuaternionsBhop 2y agoLocal by default would have been a much better choice. The entirety of my code looks like local this local that. In all my years of Lua I have only found 1 reason to use a global variable: in Love2D when loading a texture, a local variable will go out of scope and get garbage collected, resulting in a black texture, but a global variable will not. Maybe it's even been fixed by now, as that was years ago.
- runlaszlorun 2y agoHaven’t done enough Lua to know if this possible, but is that monkey patchable?
- klibertp 2y agoYes, you can control a namespace (in the form of a table, of course) in which a module you require executes. The global definitions are then placed in the table. You can implement copy-on-write using this namespace and a metatable, you can change the semantics of accessing an uninitialized (global) variable, etc. Lua is incredibly flexible, after all. Unfortunately, since you have to implement (and then maintain!) those yourself, it's hard to justify (IME) using Lua instead of a more full-featured solution (that might still incorporate Lua somewhere in the stack[0]), esp. since the main selling point of Lua is simplicity. [0] You can use something like Fennel or Haxe to compile a more structured language to Lua, or you can use an alternative implementation like Luau.
- fifilura 2y agoI have not looked at Lua but this: > I can usually accomplish whatever I need to without looking anything up" And "everything is a table" Makes it sound a lot like SQL. Edit: I prefer replies to downvotes.
- wk_end 2y agoLua isn't anything like SQL. "Table"s in Lua are like maps/dictionaries/hash tables, not relational tables.
- fifilura 2y agoBut still maybe the concepts for working with them (group by/ join/ aggregate) are similar? There are lots of things you can do with a table as a general purpose data structure. And I was curious if this was a similarity? When you say that tables are like dicts/maps, are they tables or are they dicts? And I apologise for not knowing more about Lua. Maybe i should have known better than to ask about things I dont know.
- vaylian 2y ago> Maybe i should have known better than to ask about things I dont know. It is fine to not know things. But when I look at your post, I see that you didn't ask any question. You only made statements that were based on very unfounded assumptions. But to get back to what tables are: They are key-value pairs with both array- and hashmap-semantics. By convention, arrays start at 1 in Lua. They are very similar to dictionaries in Python , associative arrays in JavaScript and other key-value data structures in other programming languages. However, lua also uses them for storing variables in environments (some people would call environment "scopes") and there are special callbacks for missing variables and accessor functions when working with these tables.
- zdragnar 2y ago> associative arrays in JavaScript You're thinking PHP. Arrays and objects are discrete things in JavaScript. You can add random properties to arrays (since they are also objects) but don't expect them to behave well when doing things line loops, getting they length, etc.
- nmz 2y agoWhat do you want it to return though? x = f() or "default value" or maybe you want it to error x = f() or error"F failed" or maybe x is an object in which case you can just setmetatable(x,{__index = function () return "" --[[default value here]] end}) or maybe you don't want nils, in which case debug.setmetatable(nil, {}) -- actually this one is complicated, but yeah, you can use this.
- int_19h 2y agoThe default should be an error, since that's the only way to prevent issues where the wrong value gets passed around a lot before finally blowing up somewhere else (and good luck debugging that). In cases where you really want to fetch the value or else get some default if it doesn't exist, there should be a way to do so that is distinct from regular dereferences and element access.
- nmz 2y agoI do not know how/why the language should magically know that something should error, if nil is not acceptable as a return then you use || or "this". if the table should not have nils then you turn it into a metatable that errors or returns whatever you want it to.
- int_19h 2y agoThe language should not "magically know" anything. It should do the safest thing, which is not to silently return a marker value for which there is no guarantee whatsoever that the caller will remember to check it. If the caller does not want to see an error, then they should use a different method of retrieving the item that is specifically defined as returning a marker value. E.g. in Python: d["foo"] # exception if missing d.get("foo") # None if missing d.get("foo", 42) # 42 if missing This follows the principle of least surprise - [] is the standard syntax for indexing, so it raises exceptions, and if you forget to check you get an error right there and then, not an unexpected but valid value (that might be saved into a variable etc and then break things much much later!). If you need a market value than you must use get(), and the very act of doing so indicates the intent to both the language and to another person reading your code.
- pseudo_meta 2y agoIf you use the lua lsp, you can make type annotations which basically work like jsdoc. With those annotations, the lsp will warn you about such issues, there is a diagnostic that's called something like `needs-nil-check`.
- arp242 2y agoI really really don't want to do type annotations. I just want to know about: variable = 1 print(varaible) It's been a while since I did Lua, but there's been a few cases where this caused massive confusion. Last I checked I couldn't really find a good way to do that; but like I said: it's been a while.
- edflsafoiewq 2y agoLuacheck will warn about unknown globals.
- pseudo_meta 2y agoI think every lua linter warns about that. So does the Lua LSP, no annotations needed.
- CRConrad 2y agoWell, yeah, you shouldn't name your variables so similarly, that's what's causing he confusion. Idunno, maybe varaible is set to "Let's groove, baby!" ? ;-)
- sureglymop 2y agoThat has been nice (at least for editing neovim configuration files). But what if I am editing anything else? For example, I have then tried to edit Wezterm config files and there are no types. I did find some types someone made online but no idea how to instruct my editor/lsp where these types are or what they are for.
- pseudo_meta 2y agoYeah, it's only for nvim or for your own lua projects. For WezTerm annotations, afaik there is currently only an open issue without much progress: https://github.com/wez/wezterm/issues/3132 https://github.com/wez/wezterm/issues/3132
- ItCouldBeWorse 2y agoMy biggest gripe with lua was that depending upon the internals of the implementation, it could "swallow" an error entirely. The program would just die in absolute silence and not give an error at all or any indication it was still running.
- wsc981 2y ago> One thing that's bothered me is that lua silently returns nil when you reference non-existing elements. That's been a pain when debugging, since a line with a typo (`a = typo`) doesn't fail, and the code fails much farther downstream (e.g. when doing arithmetic on `a`). So almost all my errors end up being "trying to do operation on a nil value", and there is no indication of why it's nil. I am also making small games with love2d. I've found you can prevent many of such issues if you: 1. Create objects with private fields, using getters and setters to access values (as function calls will crash if you call them and the functions don't exist, unlike fields). I like an approach that is somewhat similar to this: https://www.lua.org/pil/16.4.html https://www.lua.org/pil/16.4.html 2. Add assertions liberally, especially in constructors.
- widdershins 2y agoUse LuaCheck if you don't want to use the LSP. It warns about the use of globals, which is generally what you want. It's perfectly possible to design your program to use no globals.