[HN Gopher] Why Fennel?
       ___________________________________________________________________
        
       Why Fennel?
        
       Author : hk__2
       Score  : 154 points
       Date   : 2023-09-13 14:21 UTC (8 hours ago)
        
 (HTM) web link (fennel-lang.org)
 (TXT) w3m dump (fennel-lang.org)
        
       | robertlagrant wrote:
       | > Another common criticism of Lua is that it lacks arity checks;
       | that is, if you call a function without enough arguments, it will
       | simply proceed instead of indicating an error. Fennel allows you
       | to write functions that work this way (fn) when it's needed for
       | speed, but it also lets you write functions which check for the
       | arguments they expect using lambda.
       | 
       | I don't understand this; why is this a speed consideration?
        
         | munificent wrote:
         | Caveat: I haven't used Fennel but just inferring from what
         | makes sense...
         | 
         | The Lua VM that they compile to already handles missing
         | arguments with some attendant but unavoidable performance cost.
         | 
         | Fennel's own `lambda` form that they layer on top does check
         | for missing arguments, but it must do so by generating extra
         | Lua code to do those checks. That additional code has a runtime
         | cost.
         | 
         | Using `fn` avoids that extra generated code and its cost.
         | 
         | If Fennel had its own runtime and VM, then the performance
         | story for how missing arguments are handled would be different.
        
         | iimblack wrote:
         | I think they meant speed of implementation.
        
         | mpenet wrote:
         | Because it's an extra runtime check vs a direct lua call
        
         | rpdillon wrote:
         | I'm not an expert, but my understanding is the Lua has a very
         | limited grammar that is specifically designed to be parsed in a
         | single pass. This precluded Lua from performing arity checks on
         | function calls.
         | 
         | Fennel does support arity checks but it comes with a runtime
         | cost since it's implemented as a separate Lua call after being
         | transpiled from Fennel.
        
           | vore wrote:
           | The grammar shouldn't have anything to do with arity checking
           | - at runtime, you're going to know if you passed a function 2
           | arguments or 3 arguments, and due to the presence of dynamic
           | evaluation, knowing how many arguments a function takes is
           | not statically knowable anyway. My best guess is that they
           | want to avoid the overhead of a runtime check for arity.
        
           | [deleted]
        
         | sullyj3 wrote:
         | It's a runtime check. The following fennel:
         | (fn add-1 [x] (+ x 1))              (lambda add-2 [x] (+ x 2))
         | 
         | transpiles to the following lua:                   local
         | function add_1(x)           return (x + 1)         end
         | local function add_2(x)           _G.assert((nil ~= x),
         | "Missing argument x on /home/sullyj3/tmp/fn-vs-
         | lambda/fnl/x.fnl:3")           return (x + 2)         end
         | return add_2
        
         | bnert wrote:
         | Arity explanation: https://en.wikipedia.org/wiki/Arity
         | 
         | From the blurb you quoted, it sounds like Lua doesn't check
         | function argument arity natively, and fennel can. This means
         | that fennel applies a runtime check to validate if a function
         | was called with an expected arity, and if not, propagates an
         | error (however Lua does that, I do not know), hence why arity
         | checked functions are not as performant.
        
           | nmz wrote:
           | So it basically does                 function M(...)
           | if select("#",...)>3 then           error("failed arity check
           | on M()")         end       end
        
             | ravi-delia wrote:
             | pretty much, yeah
        
         | Joker_vD wrote:
         | IIRC (and I remember it quite vaguely from some random blog
         | post on the Internet) the Lua implementation uses some trick
         | that _greatly_ speeds up setting up and tearing down activation
         | frames (and has also something to do with the ability to easily
         | cross-call into C back to Lua again?), but it hinges on that
         | argument-passing /result-returning semantics being "use nils
         | for missing stuff, throw away the extras" so e.g. Python can't
         | use it to speed up its implementation of function calls.
         | 
         | Unfortunately, I can't find that blog post so take my words
         | with a grain of salt.
        
         | throwway120385 wrote:
         | This is mostly based on my experience in the past with Lua
         | circa 2015 when I developed a GUI using Crank Storyboard Engine
         | and needed to write some stuff in C because the Lua equivalent
         | code was too CPU-intensive.
         | 
         | If I remember correctly, Lua is a stack-based VM. What this
         | means is that every piece of data has a corresponding location
         | on a stack data structure in-memory. Function arguments are
         | pushed into the stack as-needed and popped in the function
         | context, and vice-versa for the function return values.
         | 
         | If you wanted arity-checking in this context, you'd have to
         | confirm that you got exactly the right number of elements on
         | the stack, meaning there would be an extra branch in every
         | function call. This might reduce performance if the branch
         | predictor gets it wrong. Plus there would need to be extra
         | instructions to count and to check the count for each pop off
         | the stack in the context of the function call.
         | 
         | This is from the perspective of calling C functions in Lua, so
         | it's probably more complicated for the VM itself when it's
         | running native Lua code.
        
           | Verdex wrote:
           | Lua is a register based VM.
        
             | neutrono wrote:
             | I think he means that the C API is stack based?
        
         | gumby wrote:
         | My memory of this is hazy, in part because I wasn't a C
         | programmer in those days, but ISTR C used to do this too. I
         | think prototypes were added (and required) only by the time
         | ANSI got involved.
         | 
         | Maybe some other OF can confirm/contradict?
        
           | ahoka wrote:
           | Fun fact: in C, if you have a signature like "int foo()", it
           | means any number of arguments can be passed (vs "int
           | foo(void)" which means no args).
        
             | fulafel wrote:
             | And there is no way for the callee to check the nr of
             | passed args, unlike in Lua.
        
             | mdaniel wrote:
             | that's ... (amazing|C for ya)                 int foo() {
             | return 0;       }       int main(int argc, char* argv[]) {
             | return foo("alpha", "beta", 1);       }       $ gcc-13
             | -Wall -Werror -o foo foo.c       # oh, sads            $
             | clang -o foo ./foo.c       ./foo.c:5:34: warning: too many
             | arguments in call to 'foo'           return foo("alpha",
             | "beta", 1);                  ~~~                   ^
             | ./foo.c:5:15: warning: passing arguments to 'foo' without a
             | prototype is deprecated in all versions of C and is not
             | supported in C2x [-Wdeprecated-non-prototype]
             | return foo("alpha", "beta", 1);                     ^
             | 2 warnings generated.
        
             | [deleted]
        
             | astrange wrote:
             | No longer true in C23, it means void now.
        
             | sovietswag wrote:
             | Good reference for that:
             | https://jameshfisher.com/2016/11/27/c-k-and-r/
             | 
             | This was also used to implement variadic functions like
             | printf before varargs, see
             | https://retrocomputing.stackexchange.com/a/20517
        
       | magicalhippo wrote:
       | Because it tastes amazing[1]!
       | 
       | Oh... not the plant...
       | 
       | [1]: https://www.foodrepublic.com/recipes/roasted-chicken-fennel/
        
         | madcaptenor wrote:
         | It does! I came in here expecting it was going to be about food
         | and was disappointed.
        
         | nultxt wrote:
         | Genuinely an incredibly flexible, amazing vegetable!
        
       | Graziano_M wrote:
       | I moved my Neovim config to fennel and haven't look back.
       | 
       | https://github.com/Grazfather/dotfiles/blob/master/nvim/fnl/...
        
         | ducktective wrote:
         | So basically Emacs with Elisp replaced with Fennel and a more
         | responsive UI...
        
           | packetlost wrote:
           | Emacs is a whoooooole lot more than an editor and Lispy
           | config language.
        
             | thih9 wrote:
             | What else is there apart from an editor and a lispy config
             | language?
             | 
             | I always thought of emacs as that, i.e. an editor that is
             | extensible and dev friendly (in contrast to vimscript). I
             | don't know much about emacs though, so this got me curious.
        
               | MassiveBonk51 wrote:
               | Well the famous joke is "Emacs is an OS that lacks a
               | decent text editor." (Yes Evil mode exists)
               | 
               | Emacs can do basically anything you write an extension
               | for it to do. It can be your calendar, your email client,
               | your rss reader or even your git gui on top of being an
               | editor. Emacs can do so much that it's daunting to start
               | using.
        
               | Tao3300 wrote:
               | Though it looks and acts like that, and can be used in
               | such a way with no problem, in a sense, you've got it
               | inside out.
               | 
               | From the GNU Emacs homepage:
               | 
               |  _At its core is an interpreter for Emacs Lisp, a dialect
               | of the Lisp programming language with extensions to
               | support text editing._
               | 
               | It's not an editor with a lispy config language, it's a
               | Lispy interpreter that comes with an editor that can
               | configure it via said Lisp.
               | 
               | It's kinda like one of those Smalltalk VMs where the line
               | is blurred between the code you're writing and the
               | environment that it runs in.
        
               | forward-slashed wrote:
               | The interactivity is one. It's easy to evaluate
               | expressions from within the editor. I am not sure you can
               | programmatically change aspects of nvim on the fly, and
               | even if so, probably not a central component of nvim
               | experience. M-x in Emacs is much more powerful than : in
               | (n)vim.
        
         | dinkleberg wrote:
         | I've been thinking about doing this, but then reminding myself
         | that this is not a wise use of my time lol. However, this looks
         | pretty nice. I might have to do it.
         | 
         | Thanks for sharing your setup, I'll be stealing some ideas.
        
           | Graziano_M wrote:
           | It was definitely not a good use of my time lol.
        
         | teruakohatu wrote:
         | Can nvim read it natively or do you need to transpile it?
        
           | Graziano_M wrote:
           | I use a plugin called Aniseed which loads first and does the
           | transpiling on the fly for me.
        
             | gorjusborg wrote:
             | I linked to aniseed originally, but nfnl is what Olical is
             | pointing people toward now?
        
           | gorjusborg wrote:
           | You don't need to transpile it if you use
           | https://github.com/Olical/nfnl
        
             | delboni wrote:
             | If you want a sample nvim setup using nfnl you can check
             | this out: https://github.com/rafaeldelboni/cajus-nfnl
        
       | nmz wrote:
       | Now I like lua and think single pass is the way to go for
       | interpreted, since you don't have the disadvantage of a slow
       | compile time no matter how big your codebase gets, BUT its not
       | great to write in. some things are (apparently) not possible,
       | which means the only solution is to transpile into it, which has
       | led to some good languages like moonscript[0], and the dynamic
       | nature is a boon as your codebase grows, which has led to teal[1]
       | which offers static type checking.
       | 
       | [0]: https://moonscript.org/
       | 
       | [1]: https://github.com/teal-language/tl
        
         | user3939382 wrote:
         | > is a boon
         | 
         | A boon is a good thing. I think you meant a problem?
        
           | agalunar wrote:
           | Perhaps they had in mind "bane".
        
         | speps wrote:
         | Don't forget Terra as well: https://terralang.org/
        
       | stonemetal12 wrote:
       | In there it says Lua uses 'for' for looping over integer ranges
       | and object ranges. They didn't like that so they broke it up so
       | that for is for integer ranges and each is for object ranges.
       | 
       | That seems strange to me. A range is a range so why have
       | different ways to iterate over ranges based on what type of range
       | it is?
        
         | giraffe_lady wrote:
         | I mean it is lua that has two different ways to loop, with
         | different syntax and semantics, but calls them both "for."
         | "Numeric for" and "generic for" are the official names, with
         | separate pages in the docs. Having different names for them
         | seems like a reasonable and not that surprising choice.
        
       | Rochus wrote:
       | There are quite many languages compiling to Lua (or LuaJIT).
       | Fennel is just one of them. See e.g.
       | https://github.com/hengestone/lua-languages.
        
         | iLemming wrote:
         | What makes Fennel a bit different is that it is a Lisp inspired
         | by Clojure. If for any reason neither of these ever interested
         | you, then, yes, Fennel would not feel any different to you.
        
           | Rochus wrote:
           | The referenced list seems to include a language for every
           | taste; Fennel is also there as one of ~10 Lisp variants.
        
       | rcarmo wrote:
       | Funny thing, I was looking at Fennel and Lua game engines... Just
       | updated with a few: http://taoofmac.com/space/games
        
       | dang wrote:
       | Related. Others?
       | 
       |  _Language Showcase: Fennel_ -
       | https://news.ycombinator.com/item?id=32349491 - Aug 2022 (2
       | comments)
       | 
       |  _Fennel: A Practical Lisp_ -
       | https://news.ycombinator.com/item?id=31029478 - April 2022 (85
       | comments)
       | 
       |  _Fennel - Lisp in Lua_ -
       | https://news.ycombinator.com/item?id=24390904 - Sept 2020 (112
       | comments)
       | 
       |  _Fennel - Lisp in Lua_ -
       | https://news.ycombinator.com/item?id=18016168 - Sept 2018 (62
       | comments)
        
       | uwagar wrote:
       | because its good for digestion
        
       | iLemming wrote:
       | If you're using a Mac, maybe check this out
       | https://github.com/agzam/spacehammer
        
       | sdfghswe wrote:
       | I didn't realize lua was a proper language until I learned that's
       | what factorio uses for its mods.
        
         | dgb23 wrote:
         | It's a very common language to embed in video games as a
         | modding and configuration tool.
        
           | SoftTalker wrote:
           | And that's the sort of thing it's _meant_ to do.
           | 
           | Tools have their strengths. Use them for that. Don't try to
           | drive a nail with a screwdriver.
        
             | whalesalad wrote:
             | this is a very vague statement. lua is used in a lot of
             | environments and is very performant. you can use it inside
             | nginx (openresty) to process requests at a pretty large
             | scale. you can use it inside of redis.
             | 
             | lua and javascript are somewhat interchangeable aside from
             | the fact that js has a much larger ecosystem.
             | 
             | sure there are situations where lua might be a bad choice
             | but based on your remarks you make it sound like it sucks
             | anywhere except inside a game engine.
        
       | giraffe_lady wrote:
       | I always say this when it comes up but fennel is very very
       | impressive as a language project. Lua is much beloved but my
       | professional experience is that working with it gets gnarly much
       | faster than most other languages. Fennel focuses on a small set
       | of the worst lua issues and addresses them without getting
       | distracted or bogged down in language design extravagances or
       | lisp nerd semiotics.
       | 
       | The decision to strictly adhere to lua runtime semantics was
       | initially repulsive to me, but I've come to appreciate the
       | incredible wisdom of that approach. The practical experience of
       | using lua is that because of the constraints of the language,
       | every lua runtime is in some ways custom & unique. This decision
       | of fennel's creator allows you to drop fennel onto _any_ lua
       | codebase, of any version, with any amount of custom freak shit
       | grafted in, and just use it. Not only use it, but hook its
       | compiler into the lua module loader system, and freely  &
       | transparently mix functions and tables between the two languages.
       | A life raft in decrepit legacy lua codebases.
       | 
       | The restraint and technical focus of this language led to me
       | checking out janet, another project of its creator. I've also
       | come to _really_ like that language, it makes some similarly
       | minor-seeming but brilliant decisions like including PEGs in the
       | core lang instead of regex.
       | 
       | Anyway try fennel, if you have to interact with a lot of lua
       | pattern match alone will improve your life. Try janet too it's
       | cool.
        
         | throwawaypml wrote:
         | I think Fennel and Janet went separate ways fairly early on,
         | and the creator of Fennel focussed primarily on Janet whilst
         | the current maintainer of Fennel is responsible for much
         | (most?) of what you see in Fennel today...So some very
         | different design choices between the two languages, i believe.
        
       | gsuuon wrote:
       | This post inspired me to look for an ML-like language that
       | compiles to lua and I found this useful list:
       | https://github.com/hengestone/lua-languages
        
       | timetraveller26 wrote:
       | I've been wanting to give Fennel a try, currently I use
       | Moonscript for my Lua transpilation (https://moonscript.org/),
       | but it has some criticisms and it can be a bit confusing
       | sometimes.
        
         | JNRowe wrote:
         | I'm a _big_ fan of moonscript, but occasionally wish it was
         | still be improved and worked on. Yuescript1 looks like it fixes
         | most of my bugbears with moonscript, and is for the most part a
         | faster2 drop-in replacement.
         | 
         | There was s little discussion here ~18 months ago3, but it will
         | feel largely circular if you look as people are suggesting
         | fennel there ;)
         | 
         | 1 https://github.com/pigpigyyy/Yuescript
         | 
         | 2 This probably only matters if you have tonnes of moonscript,
         | not just a little neovim/mpv/awesomewm config or something.
         | 
         | 3 https://news.ycombinator.com/item?id=29903133
        
       | whalesalad wrote:
       | For the clojurists this is a cool intro: https://fennel-
       | lang.org/from-clojure
        
       | eviks wrote:
       | > yet keeps a very small footprint both conceptually
       | 
       | it's only a benefit for writing simplistic things (and configs
       | for some complicated programs like a text editor or a terminal or
       | some MMORPG is already not simple), otherwise you start
       | appreciating that there is not just a single dictionary as a data
       | type etc.
        
       | cheeselip420 wrote:
       | Why does every single language landing page not have example
       | code? I don't want to read justifications. The code should speak
       | for itself.
       | 
       | Show me an echo server. Show me how you open a file and read
       | data. Show me SOMETHING. Right on the landing page. How are we
       | still doing this?
       | 
       | EDIT: I stand corrected - this is but a subpage. The actual
       | landing page apparently DOES have code.
        
         | giraffe_lady wrote:
         | This isn't the landing page, which does show a code example
         | prominently.
        
         | arvidkahl wrote:
         | Linked above is a subpage. The actual homepage at
         | https://fennel-lang.org/ has code and even an integrated place
         | to run it.
        
         | [deleted]
        
       ___________________________________________________________________
       (page generated 2023-09-13 23:00 UTC)