[HN Gopher] Fennel - Lisp in Lua
       ___________________________________________________________________
        
       Fennel - Lisp in Lua
        
       Author : tosh
       Score  : 186 points
       Date   : 2020-09-06 12:30 UTC (10 hours ago)
        
 (HTM) web link (fennel-lang.org)
 (TXT) w3m dump (fennel-lang.org)
        
       | galfarragem wrote:
       | AFAIK, for his author, Fennel is legacy. Nowadays he seems to
       | contribute only to Janet (https://janet-lang.org).
        
         | molloy wrote:
         | It's still under very active development by technomancy and
         | others, with a friendly community and lively IRC channel.
        
       | miguendes wrote:
       | Interesting project. I had never heard of a lisp flavour for lua
       | before. Looks very elegant.
       | 
       | It reminds me of hy, for python. [1] [1]
       | https://github.com/hylang/hy
        
         | dunham wrote:
         | There is another small lisp that targets both Lua and
         | Javascript called "lumen"[1]. Small enough that you can easily
         | tinker with it. I added clojure style {} literals to the reader
         | and paired it with hyperapp to write a toy web application.
         | 
         | [1]: https://github.com/sctb/lumen
        
         | rcarmo wrote:
         | If you are interested in LISP variants, check my "catalogue"
         | over at https://taoofmac.com/space/dev/LISP
        
         | Rochus wrote:
         | Plenty of lisp frontends for lua, see
         | https://github.com/hengestone/lua-languages#lisp
        
         | mumblemumble wrote:
         | I haven't spent any time with Fennel, but it seems more
         | promising to me.
         | 
         | I couldn't get comfortable with Hy. It drops so many lispy
         | things, such as let statements and persistent data structures,
         | in order to stay close to the Python substrate. (You can get
         | both from libraries, but at the cost of easy interop with
         | Python packages, which kind of defeats the whole point of being
         | on the Python platform in the first place.) It ultimately came
         | out feeling less like I was working with a lisp, and more like
         | I was working with an s-expression syntax for Python.
         | 
         | OTOH, if you think that Python, while otherwise great, is
         | really suffering for lack of defmacro, Hy absolutely succeeds
         | in getting you Python with defmacro.
        
           | rcarmo wrote:
           | I ended up dropping Hy very soon after they dropped let. Had
           | an entire blog engine written in it:
           | https://github.com/rcarmo/sushy
           | 
           | ...but I wanted Hy to be LISP, not a thin veneer over Python.
        
       | slumos wrote:
       | I wrote my simple Hammerspoon config in Fennel and am really
       | happy with it.
       | 
       | https://github.com/slumos/dot.hammerspoon
        
       | j_m_b wrote:
       | What are some projects that people are using that use Lua? Why
       | use it over something like python for scripting?
        
         | pkphilip wrote:
         | I have embedded lua in Spring Boot webapps where I required an
         | external rules files which could be easy to read for business
         | folks.
         | 
         | Example: Specialised handling for different customer types and
         | you don't want to manage all the rules in the RDBMS but would
         | rather run a separate script for each customer type and have
         | this script in a plain text format and version managed using
         | Git.
        
         | stevedonovan wrote:
         | Probably because Lua is meant to be embedded in an application
         | and provides a small, highly optimized VM. On my system Lua is
         | smaller than PCRE.
        
         | jmiskovic wrote:
         | I've made a suite of digital musical instruments for Android
         | phones in Lua. Now I'm using same language to build some VR
         | prototypes.
         | 
         | Here are some benefits of Lua over Python. It's really powerful
         | language (anonymous functions, closures, tail-call
         | optimization, full lexical scoping, coroutines...) that
         | supports many paradigms, and yet it is tiny and elegant. There
         | are few surprises and everything is explicit.
         | 
         | Runtime is easily embeddable, which means it will be more
         | readily available on exotic platforms. The interpreter is much
         | faster than Python. C code is effortless to call into with FFI
         | and resulting code looks just like normal Lua.
         | 
         | Not everything is roses. I prefer readability and less
         | verbosity of Python. The 1-indexing needs some getting used to.
         | Batteries are not included (to be more portable), so there are
         | dozens of implementations of basic things like serialization,
         | OO classes and table copying. Most online material (wiki) was
         | written very long ago and it's full of language proposals that
         | never succeeded. Some valuable resources can be found in
         | documentation of hosting frameworks (Defold, Solar2D, Roblox,
         | ComputerCraft, WoW).
        
         | gumby wrote:
         | the easiest way to put it is that you embed Lua into your app
         | (say scripts that are loaded at startup or even as a command
         | line) while it's more natural to embed your external
         | functionality into Python (e.e. numpy).
         | 
         | It's simpler to connect lua to your c/c++ datastructures than
         | it is to connect Python, and it's more complicated to write
         | little things in Python.
         | 
         | Sometimes it's easier to grab a pencil and scribble a little
         | note on a piece of paper. Sometimes it's a lot more useful to
         | type a note into your phone or computer than to deal with
         | paper.
        
         | stevekemp wrote:
         | I wrote a console-based email-client, using Lua for all
         | configuration and scripting needs.
         | 
         | Using Lua is generally done because it is easy to embed inside
         | a host-application. While it is possible to embed Python, Perl,
         | or other languages, they're relatively heavyweight and not so
         | commonly used in that case.
         | 
         | In my own application I always felt annoyed that mutt didn't
         | have "real" scripting. Just an ad-hoc configuration that made
         | lots of things possible, but neglected some basics (such as
         | loops and similar).
         | 
         | Configuring a mail-client in Lua was a nice exercise, but
         | eventually I moved on to pay for gsuite rather than self-
         | hosting a mailserver of my own so it became a "done" project.
         | Definitely a useful learning experience though, experimenting
         | with user-interface, embedded scripting, and going through lots
         | of learning relating to MIME-handling & etc.
        
           | fit2rule wrote:
           | Your project sounds cool - is it possible to process email
           | with Lua scripts, so that I could use a mailbox as a business
           | process queue that is also user-friendly, while having a
           | suite of Lua apps processing the mailboxes? If so, care to
           | share details of your project if its open/available?
        
         | masklinn wrote:
         | Lua is way more common for game scripting than Python. One of
         | the few major games which used Python I can think of was Civ
         | IV, and Civ V switched to Lua.
         | 
         | Lua is smaller, easier to embed interface / interact with (e.g.
         | it's way less ceremony to expose a native function to Lua than
         | to Python), and tends to be faster, especially when jumping
         | back and forth between the engine and the scripting. Embedding
         | / scripting (within a larger program) is the original use-case
         | of Lua, not so Python.
         | 
         | I believe it's also much easier to secure / sandbox (remove
         | bits you don't want script writers to have access to) as well,
         | the stdlib is smaller and I think it has less interactions
         | between modules.
         | 
         | Python embedding / scripting tends to be more common for
         | software where the securing / restriction aspect is smaller but
         | flexibility & larger embeds are necessary e.g. 3D, CAD and
         | other "production pipeline" software tends to be scripted with
         | Python.
        
           | pansa2 wrote:
           | > _I believe [Lua is] also much easier to secure / sandbox
           | [than Python]_
           | 
           | Yes. C code that embeds the Lua VM has total control over
           | which functions are exposed to the Lua code. It's possible to
           | create a VM that, for example, has no access to the
           | filesystem.
           | 
           | AFAIK it's not possible to do that if you embed Python.
           | Dangerous functions like `open` are always available and
           | sandboxing facilities have to try and prevent untrusted code
           | from getting a reference to them. Unfortunately, there are
           | numerous ways to work around these restrictions and obtain
           | access to dangerous functions, e.g. via `__builtins__`.
           | 
           | Another reason running untrusted Lua code is considered
           | fairly safe is that the VM is well-engineered and has a
           | history of very few bugs [0]. However, the latest 5.4.0
           | release seems to have more bugs than older releases.
           | 
           | It might still possible for untrusted Lua code to use 100%
           | CPU and hang a program, or to read data from the embedding
           | process using a Spectre-style attack (although even that's
           | unlikely because the Lua VM is an interpreter rather than a
           | JIT compiler). However, it's quite possible to secure an
           | embedded Lua VM to prevent it from doing things like
           | accessing arbitrary files.
           | 
           | [0] https://www.lua.org/bugs.html
        
             | philsnow wrote:
             | > the Lua VM is an interpreter rather than a JIT compiler
             | 
             | There's also luajit, but I don't know how common it is vs
             | "just Lua". My impression was that luajit was used pretty
             | often though.
        
             | formerly_proven wrote:
             | Sandboxing Python used to be and still is hairy and very
             | hard (it requires intricate knowledge of CPython, because
             | you are going to inspect the AST for unwanted things and do
             | some other relatively low-level stuff) and Python is also a
             | pretty big dependency (~5-10 MB). I think many recent-ish
             | additions to Python may make sandboxing easier (e.g. audit
             | hooks, subinterpreters), but it's still hard and messy.
        
         | formerly_proven wrote:
         | Lua is a tiny, relatively simple language with a simple data
         | model built on a small runtime that's very fast for an
         | interpreter and easy to embed into C/C++ applications (once you
         | dealt with the stack, mentally or otherwise). Startup time is
         | ~nil.
         | 
         | Python is a large, complex language with an exceedingly
         | complicated data model built on a runtime where the core
         | interpreter is about ~4 MB, which is also a pretty slow
         | interpreter (mostly due to the exceedingly complicated data
         | model). Python is certainly not hard to embed on an API level,
         | but somewhat annoying to package up for a build. Python is very
         | hard to sandbox, whereas Lua is basically sandboxed by default.
         | Startup time is on the order of ~100-200 ms.
        
         | chgibb wrote:
         | We're using Lua as a base for bringing Flutter into other
         | languages https://github.com/chgibb/hydro-sdk
        
       | fortran77 wrote:
       | The reason I used Lua was its "accessibility" -- so end users can
       | script -- and not necessarily for the beauty and elegance of the
       | language. It was also very easy to integrate into a C++ project.
        
       | mumblemumble wrote:
       | A nice summary of what Fennel's about here:
       | http://jakob.space/blog/thoughts-on-lisps.html#org4d7f824
        
         | masklinn wrote:
         | It's kinda weird that the only mention of Clojure is
         | 
         | > Clojure's license makes it a complete non starter for me,
         | sorry. Live free or die.
         | 
         | when at first glance fennel looks a lot like clojure e.g. `fn`,
         | square brackets, {} for maps / table literals.
        
           | SahAssar wrote:
           | > when at first glance fennel looks a lot like clojure e.g.
           | `fn`, square brackets, {} for maps / table literals.
           | 
           | Aren't those mostly inherited from lua and present in a lot
           | of different languages invented before and after clojure?
        
             | masklinn wrote:
             | Lua defines functions with the `function` keywords, and as
             | most other C-style languages uses parenthesis to wrap the
             | function parameters, not brackets.
             | 
             | It does use `{}` for table literals but requires the `=`
             | and `,` separators, where fennel (and clojure) uses no
             | internal separator at all: a map literal is a pair of
             | braces around a _plist_ (https://www.gnu.org/software/emacs
             | /manual/html_node/elisp/Pr....
             | 
             | Historically, lisp have used something around "define" to
             | define functions (e.g. define, defun), parenthesis as
             | essentially the only grouping, and would use macros or
             | special-forms rather than complex literals.
             | 
             | Clojure is the first lisp I know of (so I may well have
             | missed a predecessor which inspired it) which largely
             | diverged from that.
             | 
             | [0] clojure allows commas but ignores them entirely, I
             | don't know whether fennel allows them as well
        
               | lispm wrote:
               | If we think Clojure is a 'diverging Lisp', then there are
               | other diverging Lisps with different syntax like MDL,
               | Logo, Dylan, even JavaScript. Some Scheme code uses
               | angular brackets.
               | 
               | Historically core Lisp has left other grouping character
               | or syntax to sublanguages or new data types. There are
               | many examples for that. This is usually done via reader
               | macros, which open up the s-expression reader to the
               | programmer.
               | 
               | This is a Joshua rule:                   (defrule
               | grandfather-determiner (:backward)           ;; there are
               | 3 ways to find your grandfather           IF [or [is-
               | genetic-grandfather-of ?gramps ?kid]           [is-
               | grandfather-thru-step-parent ?gramps ?kid]           [is-
               | step-grandfather-of ?gramps ?kid]]           THEN [is-
               | grandfather-of ?gramps ?kid])
               | 
               | Many internal or external domain specific languages for
               | Lisp use special syntax and defining forms, since their
               | authors either believed that it's easier to use in
               | general or that it was necessary for 'end users' of their
               | systems. Early examples were maths systems like Macsyma,
               | which were programmable, but addressed mathematicians as
               | audience. Logo, which was Lisp for kids. One of the first
               | theorem provers had the first ML as the programming
               | language interface for its users.
               | 
               | Historically Lisp 2 was supposed to get rid of simple
               | s-expressions on the surface. There was a different
               | syntax defined for it.
        
               | masklinn wrote:
               | I was mostly talking about diverging in the way Fennel
               | had.
               | 
               | > Historically core Lisp has left other grouping
               | character or syntax to sublanguages or new data types.
               | 
               | Sure, but Clojure uses other grouping characters for the
               | main dialect itself, and Fennel uses very similar
               | deviations from the "Lisp baseline", hence my wondering
               | about the inspiration.
        
               | lispm wrote:
               | Square brackets have been used in some Scheme for a long
               | time. There are also Scheme books which use them in code.
        
               | masklinn wrote:
               | Used them to define the formal parameters of a function?
               | Because that's what I'm referring to. Fennel uses
               | (fn [param*] expr*)
               | 
               | for function definition, which is also how it is spelled
               | in Clojure.
        
               | lispm wrote:
               | One can use them everywhere instead of parentheses.
        
           | nonbirithm wrote:
           | I wish Lua had immutable data structures with memory sharing.
           | It would make the designs of some things much more
           | performant.
        
       | vsurabhi wrote:
       | This and a recent feature addition to neovim (passing lua
       | closures to vimscript functions [1]) should make a good
       | substitute for elisp to configure neovim.
       | 
       | [1] https://github.com/neovim/neovim/pull/12507
        
       | merricksb wrote:
       | If curious, see previous discussion from 2018
       | 
       | https://news.ycombinator.com/item?id=18016168
        
       | minxomat wrote:
       | Here's an example web app hello-world in Fennel, parsing requests
       | and responding with HTML rendered from the S expressions:
       | https://gist.github.com/turbo/4388c9ad19028560053951a25b3b45...
        
         | yawn wrote:
         | Thanks for posting this. I took a look at Fennel a few months
         | ago and although they list 2 web frameworks on the front page,
         | there's little documentation (that may have changed since then)
         | about how to interface with other Lua projects. I kept running
         | into things I couldn't figure out when working with the
         | existing Lua ecosystem and projects.
        
           | erikcw wrote:
           | I've been using it quite successfully in a large OpenResty
           | project.
           | 
           | While you're right that there aren't any docs on working with
           | any of the 3rd party projects listed in the homepage - I
           | found that it was pretty straight forward to use as a drop in
           | Lua replacement by examining the compiled Lua from the online
           | REPL. I was surprised how clean the Lua output is. There is
           | really no magic here. I believe one of the project goals is
           | to stay as close to Lua semantics as possible. Basically just
           | lisp flavored Lua.
           | 
           | In my project I just use the compiled .fnl files as I would
           | any of other .lua file.
           | 
           | Is something specific you're getting stuck with? I'd be happy
           | to try to point you in the right direction.
           | 
           | It's really nice! I encourage you to give it another try.
        
       | rcarmo wrote:
       | It should be noted that 0.6.0 came out 3 days ago, with a few
       | improvements:
       | 
       | https://fennel-lang.org/v0.6.0/
        
       | molloy wrote:
       | A lot of the questions in this thread are answered here:
       | https://fennel-lang.org/rationale
        
       | rudolfwinestock wrote:
       | A Hacker News regular, technomancy (the same guy behind the
       | Atreus keyboard), has contributed a great deal to the Fennel
       | language. https://builds.sr.ht/~technomancy/fennel-lang.org
       | 
       | I'd like to see him visit this thread.
       | 
       | https://news.ycombinator.com/user?id=technomancy
        
         | reitzensteinm wrote:
         | Not to mention lein for Clojure. He only posts here a few times
         | a year which might be how he manages to be so prolific.
        
         | bokchoi wrote:
         | And if you haven't checked out his pico-8 game he used fennel
         | to write, you ought to. It's great!
         | 
         | https://technomancy.us/190
        
       | manexploitsman wrote:
       | Why do you need all of those brackets?
        
       | remix2000 wrote:
       | In the realm of Lua Lisps, there is also Urn: https://urn-
       | lang.com/
        
       | aasasd wrote:
       | I really wish Lua were popular for small-scale utility scripting
       | instead of Python and JS. Because Lua is way snappier: even with
       | language translation, plenty of Fennel scripts will run under
       | Python's startup time. Likewise, Lua seems like a great fit for
       | small mobile apps and automation (dunno about threading though,
       | but I seem to have read that Lua can do threads with a _library_
       | ).
       | 
       | My primary woe with Lua is the absence of 'null'. You can't
       | preserve structure of deserialized tables if there are nil values
       | in them, so you can't really build API middleware and such,
       | without extra effort for that (so you'd also not be able to use
       | functional libraries like Penlight in your middleware).
        
         | ebg13 wrote:
         | Lua will never be more popular without a proper standard
         | library.
         | 
         | Leaving everything up to the user so that you have to manually
         | implement (or hunt the web for) even the most basic features is
         | mega annoying. How many millions of people need to rewrite
         | string.startswith?
         | 
         | The whole "sequence iteration stops at the first internal hole
         | and therefore the # operator doesn't do what you think it
         | should" gotcha is extremely user hostile.
         | 
         | Metatables are cool and all, but holy crap are they confusing
         | for Lua newbies. Having an integrated class system would go a
         | long way.
        
           | aasasd wrote:
           | Ah, yes, the table length/ iteration thing probably deserves
           | the second place or a tie in the annoyances.
           | 
           | The library thing is eh: just grab Penlight if you aren't
           | running Lua on a microchip.
        
           | dwheeler wrote:
           | Agreed. One of the reasons that Python grew popular so fast
           | was its "batteries included" approach. When a developer needs
           | to do some common thing, it's really helpful to have one
           | obvious way to do it that is highly reliable and well
           | integrated with the rest of the system.
        
           | fit2rule wrote:
           | 1. Luarocks. 2. I regularly carry these little enumerables
           | around with me and use it so frequently I found it quaint to
           | be reminded of the 'hole problem':                   --- get
           | all packed entries, until gap         -- func on the provided
           | list         -- @param list table to be inspected         --
           | @param func do func what you func want         table.each =
           | function(list, func)           for i,v in ipairs(list) do
           | func(v, i)           end         end              --- get all
           | entries, packed or not, until completion         -- func on
           | the provided list, completely         -- @param list table to
           | be inspected         -- @param func do func what you func
           | want         table.all = function(list, func)           if
           | (list ~= nil) then             for i,v in pairs(list) do
           | func(v, i)             end           end         end
           | 
           | Disclaimer: I love Lua and would us it for everything if I
           | could.
        
             | ebg13 wrote:
             | Do you also carry a table deepcopy with you? What about
             | string.trim?
             | 
             | And LuaRocks is a trash fire that doesn't integrate well
             | with Lua's primary role as an embedded plugin engine and
             | leaves you to waste your time in endless discovery of a
             | slew of unmaintained packages that all do the same thing in
             | different ways and with different bugs. Want to
             | collaborate? I hope everyone is familiar with "classy" and
             | not "oops" or "objectlua" or "Luaoop" or "lobject" or
             | "classyng" or "klesi" or "halo" or "lua-c3class" or "pool"
             | or "middleclass" or "Sunclass" or any other module that
             | implements one of the half dozen official recommendations
             | for faking classes with metatables or closures. It also
             | becomes a huge "left-pad" risk.
        
               | fit2rule wrote:
               | Table deepcopy: table.unpack() does pretty much
               | everything I've ever needed it to do, but for those
               | tricker tables, there's always
               | https://gist.github.com/tylerneylon/81333721109155b2d244
               | - and I freely admit that yes, the link to that gist is
               | in my "Lua dev notes" bookmarks file, which I refer to
               | often.
               | 
               | Hmmm ... string.trim: umm, not really something I find I
               | need, a lot of times.. but as usual, Lua-users provides
               | some incite into why, exactly, its not always as simple
               | as one might think. (http://lua-
               | users.org/wiki/StringTrim)
               | 
               | As for your brilliant discourse on Luarocks, ok. Not
               | gonna get any resistance from me on that. I know the pain
               | you describe. But I have had success with using it to
               | copy environments on other machines 99% of the time ..
               | which is not what I could say about the hell that python
               | has put me through, at times. But I guess that's par for
               | the course.
        
           | pansa2 wrote:
           | > _Lua will never be more popular without a proper standard
           | library._
           | 
           | How would you add a large standard library without
           | compromising Lua's main purpose - to be a lightweight,
           | embeddable language?
        
             | ebg13 wrote:
             | It would still be lightweight and embeddable with common
             | sense pure Lua functionality like classes and major utility
             | methods like string.startswith/string.endswith/string.trim/
             | string.split/table.deepcopy. You don't have to integrate a
             | multiprocessing web server for different operating systems.
             | 
             | Instead you're left with bullshit community essays like
             | http://lua-users.org/wiki/SplitJoin which shows pages and
             | pages of different user attempts for one extremely common
             | function, many of which explicitly do not work!
             | 
             | Lua has its strengths, but faffing about refusing to just
             | standardize the right way to do things is super user-
             | hostile.
        
             | stjohnswarts wrote:
             | have a "smol-lua" that is a proper subset of the "hugely-
             | lua" ? I really wish there were more good options for that
             | for python.
        
         | samatman wrote:
         | could you expand on that a bit?
         | 
         | null and nil are effectively synonyms, and I'm having
         | difficulty understanding what about Lua's use of nil has caused
         | problems for you.
        
           | aasasd wrote:
           | In Lua, nil is not a value. It's an all-encompassing void in
           | which variables are suspended when not having some other
           | value--simultaneously existing and non-existing: both
           | manifest variables or fields of this reality and the infinite
           | multitude of potential variables of other timelines. And you
           | can't tell which reality you're in.
           | 
           | So it's useless for interfacing with 'null's of other
           | languages.
        
             | samatman wrote:
             | In Lua, nil is assuredly a value. `return type(nil) ==
             | 'nil'` is a valid program which returns `true`.
             | 
             | It doesn't have the semantics you're used to from other
             | languages. I happen to prefer Lua's approach, I think the
             | distinction between undefined and null is clunky and I'm
             | glad that `undef` didn't make the cut in 5.4.
             | 
             | You presumably disagree, which is fine.
             | 
             | There is one rough edge I've encountered, which is down to
             | a serious wart in the standard library: `table.insert(tab,
             | value)` inserts the value at the end of the array portion,
             | which in Lua we express as `#tab + 1`.
             | 
             | But `table.insert(tab, index, value)` is what's used to
             | insert into another slot in the array portion. This is a
             | serious mistake which only prevails for historical reasons.
             | 
             | I beg of you: never shift the meaning of parameters around
             | when you add more of them. Nothing good will ever come of
             | this!
             | 
             | As a result, `table.insert(a, b, nil)` doesn't do the same
             | thing as `table.insert(a, b)`. In the three parameter
             | version, `b` is an index, in the two parameter version,
             | it's a value.
             | 
             | It's not possible to write this sort of monstrosity in pure
             | Lua, where nil is well behaved; but `table.insert` is a
             | builtin, implemented in C, or whatever the host language of
             | your particular Lua implementation happens to be.
             | 
             | In C, there's a difference between a `nil` on the parameter
             | stack, and a shorter parameter stack. A Lua programmer will
             | never see this: passing a third `nil` or just calling a
             | function with two parameters will have the same effect.
        
           | mumblemumble wrote:
           | Lua doesn't distinguish between, "the key is not in the
           | table," and, "there is a value for that key, and the value is
           | nil." Setting the value for the key to nil simply erases it
           | from the table.
        
             | samatman wrote:
             | Ah, so the problem is JSON compatibility.
             | 
             | Yeah, I can see that. But I have to say: I think the
             | mistake was on JSONs part. That's what `nil` should mean,
             | imho: the value of anything which has no other value.
             | 
             | An object { "foo" : 12, "bar" : null } could just be {
             | "foo" : 12 }, and if I was expecting a "bar" field, well, I
             | can set it to null/nil myself.
             | 
             | Other people have pointed out ways to work around it, so I
             | won't go down that road myself.
        
             | nikki93 wrote:
             | You can just create a sentinel value and use that. eg.
             | `local mySentinel = {}`. Then insert that value when that's
             | the behavior you want. `nil` on its own rarely makes for a
             | good semantic understanding of what value is actually in
             | the table anyways.
             | 
             | Also, in Lua 5.4, the behavior is different -- you need to
             | do `t[key] = undef` (which is the only context you can use
             | `undef` in). And `nil` can actually be a value in a table.
             | Not saying what's better or worse, but that the behavior in
             | 5.4 is different.
        
               | pansa2 wrote:
               | Did `undef` actually make it into 5.4? I thought it was
               | removed during the beta period.
        
               | samatman wrote:
               | It was.
        
               | aasasd wrote:
               | Do libraries like Penlight know about your sentinels or
               | 'undef'? Maybe in ten years they will use undef, or maybe
               | you whipped up your own functional library and keep it
               | optimized and full-featured. But now we have what we
               | have.
               | 
               | Besides, please tell: if you receive an empty object as a
               | value in JSON, how do you preserve it in your 'sentinel'
               | approach? Gotta need another special value for that.
        
               | nikki93 wrote:
               | For the JSON case, it doesn't make sense to use an empty
               | object as a sentinel, for sure. JSON parsers usually have
               | their own sentinel for `null`. Lua has a lot of issues,
               | but `nil` being not-present hasn't been an issue that has
               | come up a lot in practice. If you have any specific cases
               | where that has been an issue, would be interesting to
               | hear about them.
        
               | aasasd wrote:
               | As I wrote in the first comment, the use-case is e.g. API
               | integration, which is what 'scripting' often is, these
               | days. More widely, any transformations or filtering or
               | helper code where you accept structures and pass them on
               | after mild fiddling--again, quite typical use for Python
               | or JS if you ever pipe data between scripts in the
               | terminal or over the network. You don't put your data
               | schema in each of those scripts and maintain them on
               | every change at the source. Imagine implementing `jq` in
               | Lua with all those 'sentinels' throughout the whole
               | function library.
               | 
               | The issue is that interoperability is crippled. The fact
               | that you haven't so far run into these use-cases doesn't
               | help with the problem that an entire, very common, class
               | of functionality can't be done without tracking those
               | nulls at each and every step with some crutches that
               | bring their own troubles.
        
               | nikki93 wrote:
               | Yeah I actually don't think Lua is great for those
               | things, tbh. Lua is not a good tool for manipulating JSON
               | --JavaScript is probably sensible for that (it is
               | JavaScript's object format, after all). And yeah I don't
               | think it's good to use a bunch of external libraries in
               | Lua, since as you say there's not a common ground for how
               | data is organized. The libraries I rely on are are more
               | native integration things like lpeg, luasocket, luasec,
               | love2d, ... They've all been quite good. And yeah you
               | keep saying 'sentinels' in quotes but honestly it's
               | worked fine when using lua-cjson. There's always an
               | impedance mismatch between JavaScript's object format and
               | Lua's though. Lua also allows non-string keys which are
               | great in Lua but not a thing in JavaScript, and in
               | practice I've found the array/object-table mismatch more
               | problematic than `nil`/`null` and so on.
               | 
               | I've mostly applied Lua for embedding in game engines,
               | and to that end there's nothing that comes close, short
               | of rolling your own VM that's exactly built the way you
               | want. The main way to use it I think is to embed it
               | somewhere and build up the set of utilities / libraries
               | that you need to script over. But yeah it's not great for
               | API glue code bc. APIs tend to bias toward JavaScript /
               | JSON and other ways of doing things.
        
       | sillysaurusx wrote:
       | Lumen - Lisp in Lua and JavaScript: https://github.com/sctb/lumen
       | 
       | Scott Bell wrote a lot of that. I was fascinated by the self-
       | hosting technique. The whole repo is so small that you can almost
       | dismiss it as some kind of academic toy, if you don't realize
       | it's a full-featured production-grade lisp.
       | 
       | (Not to take anything away from Fennel! The more lisp, the
       | better.)
        
         | tgbugs wrote:
         | I knew about Fennel, but did not know about Lumen. Thanks for
         | the pointer!
         | 
         | edit: Looking at the git history is very educational for how to
         | bootstrap a self hosting system like this. Fascinating.
        
         | pmoriarty wrote:
         | Would someone be so kind as to compare Lumen to Fennel?
        
       ___________________________________________________________________
       (page generated 2020-09-06 23:00 UTC)