giraffe_lady 10 months ago

I've talked about it a few times before when it comes up but I love this language and think it's just an incredible technical accomplishment.

Lua is beloved and I have a ton of respect for that project in itself, it's definitely one of the seven wonders of the programming world. But the (well-considered) compromises for its intended use as an embedded scripting language make it pretty rough for large complex projects.

Fennel is just an extremely focused aid to some of the worst lua warts. Pattern matching alone is incredible for the overloaded tables lua uses. The macro system is excellent, and since a lot of the time what you're doing with lua is defining a DSL anyway it gives you more powerful tools for that.

I initially recoiled but I now think it was a genius decision to do it with just a few special forms over the lua semantics. Other than the lisp syntax there's very little new to learn to use it. And the best part is that it hooks into the lua module loader system so you can freely mix tables and functions between the two, a life changer in legacy codebases.

Can't say enough good things about fennel. There are a lot of languages that I like but it's one of the only ones I think is actually good. I rarely write normal lua anymore it's just so flexible.

  • techsuvara 10 months ago

    I ported LUA to the Nintendo DS in 2007. It wasn't designed for embedded devices back then, let me tell you, it was one hell of a headache to chop down to size.

    Not sure if the market for LUA has changed since then...

    Still, it's a great language for scripting.

    • 8372049 10 months ago

      Lua isn't made for embedded devices, it's made to be embedded into other programs and systems. It is widely used as a scripting language in games. There's even APT malware that has used Lua as a scripting language.

      • squarefoot 10 months ago

        > Lua isn't made for embedded devices

        True, however it was later adapted and ported to a number of small architectures. NodeMCU is just the most popular one of them as the EluaProject started years before even the ESP8266 was available. https://eluaproject.net/

dang 10 months ago

Related:

Why Fennel? - https://news.ycombinator.com/item?id=37497131 - Sept 2023 (102 comments)

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: A Practical Lisp - https://news.ycombinator.com/item?id=30963628 - April 2022 (2 comments)

Fennel 1.0.0 Released - https://news.ycombinator.com/item?id=29221245 - Nov 2021 (1 comment)

Fennel 0.8.0 Released - https://news.ycombinator.com/item?id=25842797 - Jan 2021 (1 comment)

Raymarching with Fennel and LÖVE - https://news.ycombinator.com/item?id=24835766 - Oct 2020 (3 comments)

Fennel – Lisp in Lua - https://news.ycombinator.com/item?id=24390904 - Sept 2020 (112 comments)

Neovim Configuration and Plugins in Fennel Lisp - https://news.ycombinator.com/item?id=21676606 - Dec 2019 (19 comments)

Fennel – Lisp in Lua - https://news.ycombinator.com/item?id=18016168 - Sept 2018 (62 comments)

azhenley 10 months ago

"you can use Fennel right here without installing anything"

It sits at 99% forever.

freilanzer 10 months ago

MoveOrDie and Acro were made with Löve and Lua. Does anyone know if I can make a 2d game with fennel alone, without touching Lua? Alternatively, what would be a better choice for simple 2d graphics (Python would be preferred)? I want to experiment with something like Dwarf Fortress.

  • donio 10 months ago

    Depending on your preferred workflow you would typically have a tiny loader stub in a .lua file that you never need to touch and all of your code in Fennel. You can still add third party Lua libraries if you desire and seamlessly call back and forth between these and your Fennel code. You can even have a live REPL to eval code in your running Löve session.

  • rainingmonkey 10 months ago

    Lua is a very simple language. If you're coming from Python, it's probably even quicker to learn vanilla Lua (and Löve) than using something like Moonscript or fennel.

    If you're set on Python there is PyGame. I haven't touched it for a number of years but back then it seemed less polished and waaay less performant than Löve.

  • trenchgun 10 months ago

    >what would be a better choice for simple 2d graphics (Python would be preferred)? I want to experiment with something like Dwarf Fortress.

    If you want to experiment with something like Dwarf Fortress, you don't need 2d graphics. You can just start with ASCII-graphics like Dwarf Fortress did.

    • freilanzer 10 months ago

      True, but at some point I need to integrate graphics, so I don't think it's a bad idea to have simple tile graphics in place. Also, I would need some kind of inventory, text fields, etc. and they might be much easier with a framework that supports them - as you see, I have next to no experience in this area.

  • ejflick 10 months ago

    You'll always need to deal with a bit of Lua afaik. If you like fantasy consoles, you can use TIC-80[1] to not have to deal with any Lua.

    [1] https://tic80.com/

asymmetric 10 months ago

Has anyone tried writing their NeoVim config in Lua? Is this a good use case for Fennel?

  • Agentlien 10 months ago

    I just finished converting my rather large (just under 500 lines) init.vim to Lua. It took way longer than I had hoped. I feel like I've forgotten the motivation and what benefits it was supposed to bring. At this point I really don't want to consider another conversion, using Fennel or otherwise.

  • adregan 10 months ago

    I think about writing the config in fennel all the time, but I’m not a big config tinkerer and already worry about struggling with Lua when I have an upgrade gone awry.

    I’ve found the neovim ecosystem to churn way more in recent years than it did when I initially started using it 8 years ago. It really reminds me of the JS ecosystem of the past decade: full featured plugin that works great decides to strip things back so that it’s functionality is all plugable and you suddenly have to wade through 2 major release’s migration docs to get things kind of working like they were before. I digress to point out why it might be hard to have yet another layer to translate through. Though if you don’t have kids, I’d say “go for it!”

  • adelarsq 10 months ago

    I have 3500 lines config file in Lua that I have converted from VimScript last year. I see that Lua it's way easier to maintain than VimScript.

    Fennel solves some Lua kirks, so I think that is a good use case, since Fennel has some cool features that can help to maintain the code. Right now I am moving the plugins that I maintain to Fennel.

    If interested take a look on the https://github.com/Olical/nfnl and https://github.com/gpanders/fennel-repl.nvim plugins.

  • asymmetric 10 months ago

    Edit: I meant writing it in Fennel

mikemee 10 months ago

Strongly agree. We liked Fennel so much we adopted it for building our mobile apps. We have a SQLite + Lua core that handles business logic and increasingly also view and controller logic with a thin native wrapper for iOS and Android. With over 100k downloads and active users, it’s proven itself stable and practical.

It’s a convenient way to access the immense power of SQLite, with the succinctness of a lisp-like syntax. Throw in tests that execute at 350 tests per second and it’s a fast, stable development platform.

Right now we’re building a wrapper to display graphics sufficient for simple puzzle games so we can generate the layouts and handle interactions also in Fennel (by mapping to native iOS and Android views). It also does hot reloading in the iOS simulator. Very much a WIP though. We haven’t shipped this part yet.

Fun times. Stable. Small. Uncomplicated. Great community.

indigo0086 10 months ago

Would someone explain the function of scripting languages. Why use a scripting language spun off from another language than use the original host language. What does lua offer as a scripting language when offering it as a scripting language?

  • hasanhaja 10 months ago

    They offer a higher level abstraction that might make interacting with the underlying APIs a little more egonomic. For example, Python being used a scripting language for AI and other data science things.

    The performant APIs that the Python wrappers call are powerful but it might be a little cumbersome to use. A library I used a lot in university was the OpenCV through the native C++ APIs, the Java API and the Python API; the Python version felt a lot easier to work with.

  • fwip 10 months ago

    Other people have given good examples about scripting languages in general. But one thing that Lua in particular excels at, is being embedded in other programs. For example, it's a common language for video games to use, both for internal scripting and external modding.

    For internal use, you give the game designers a higher-level and easier-to-use language with quick feedback (no recompiling your game just to change some logic). For modders, it lets you sandbox their contributions to a specific API, but let them implement arbitrary logic inside of it. This lets users install mods from untrusted sources with confidence that it's not going to crash their computer, delete their data or install a keylogger.

  • akkartik 10 months ago

    They enforce invariants automatically for you that you might have to manually deal with in the host language. Examples:

    * You'd have to remember to free heap allocations in C. Lua does it for you.

    * You might want to always access a particular object's field through a function rather than directly. If you programmed in C it's your responsibility to not mess this up, you won't get any warnings or errors if you forget. A scripting language could automatically call the function when you try to access the field.

    * You might want to ensure that any switch case over a enum always considers all possible values of the enum. C wouldn't help you here, but Fennel's infrastructure for pattern matching would.

  • bobajeff 10 months ago

    Ideally all languages would be quick to program in but the reality is that some languages have really long compile times and are unsuitable for quick prototyping, experimenting, creating proof of concepts, or small programs. That's where scripting languages come in handy.

    • imtringued 10 months ago

      Nothing prevents anyone from building an ABI compatible interpreter where only parts of the program are compiled.

      • idle_zealot 10 months ago

        I think the bigger problem is a language design one. Scripting languages are often easier to use than more performant ones because they make a lot of choices for the developer (automatic allocation and garbage collection, doesn't expose reference versus value, no pointers, everything is a table/object/whatever). A runtime can try to make inferences about how language features are being used in order to speed up execution or reduce memory use, but usually even then things end up being less efficient than if the programmer had to actually make choices about memory allocation, if/when to free things, etc.

      • bobajeff 10 months ago

        Nothing save for time, skill and enough financial support. Sure. While we're at it why not make a Web Browser too? Technically, nothing stops us.

Closi 10 months ago

Some of the syntax choices seem a little strange to me, but I maybe just don't understand the language.

What's the reason for (/ num1 num2) rather than just num1/num2 for division for example?

  • agent281 10 months ago

    There is a whole branch of programming languages that use prefix notation like that. It's one of the oldest branches starting in 1958. The benefit of the prefix notation is that it is really easy to write macros and embed Domain Specific Languages (DSLs). It's an interesting part of the programming world. I would recommend checking it out!

    https://en.wikipedia.org/wiki/Lisp_(programming_language)

  • Y_Y 10 months ago

    A lot of people have asked the same question over the years, and by now there are some good answers.

    For example many lisps implement SRFI 105: Curly Infix https://srfi.schemers.org/srfi-105/ which lets you write {a * b + c / d} instead of (+ (* a b) (/ c d)).

    Afaik Fennel doesn't have this, but that's fine because it has macros!

      (macro infix [expr]
        (let [stack []
            ops {
              "+" (fn [a b] (+ a b))
              "-" (fn [a b] (- a b))
              "*" (fn [a b] (* a b))
              "/" (fn [a b] (/ a b))}]
          (fn [item]
            (if (number? item)
              (table.insert stack item)
              (let [op (get ops item)
                  b (table.remove stack -1)
                  a (table.remove stack -1)]
              (table.insert stack (op a b)))))
          (each [_ v (ipairs expr)]
            (infix v))
          (first stack)))
    
    
    And now you can do:

        (infix [1 + 2 * 3 - 4 / 5])
        ; => 5.2
    • peeters 10 months ago

      I can't quickly parse this in a way that makes 5.2

          1 + (2 * 3) - (4 / 5) = 6.2 (PEMDAS)
          1 + (2 * (3 - (4 / 5))) = 5.4 (greedy)
          (((1+2) * 3) - 4) / 5 = 0.4 (non-greedy)
      
      Was it a typo or is it using some other grouping I don't understand?
      • Y_Y 10 months ago

        Typo, I should have actually run the code! That macro doesn't have any fancy operator precedence rules, but you could certainly add them.

  • antiquark 10 months ago

    Call me old fashioned, but I always thought syntax like "x = a * b + c" was a leap forward.

    • whartung 10 months ago

      To a point, but at a cost.

      In C++, there's 17 levels of precedence across 60 operators, with varying associativity.

      In many languages, due to precedence, 1 + 2 * 3 = 7, but in others, like Smalltalk, it equals 9. In those languages, its purely left to right, with no precedence. But at a casual glance, they look identical. And for someone bouncing back and forth, they better ensure they have the right hat on when they start writing out equations.

      In prefix languages, this is not an issue. Everything looks like a function.

      +, -, sqrt, sin, draw.

      You also can have niceties like (+ 1 2 3 4), which simply adds up all of the arguments, in contrast to (+ 1 (+ 2 (+ 3 4))). But, that's not different grammatically from (sin (sqrt (abs x))), (f1 (f2 (f3 x))), which appears like sin(sqrt(abs(x))) in infix languages, not much different really at all.

      Clearly there are benefits to infix presentation, and for basic (or, even BASIC!) use its very approachable.

      But underlying it, there's some definite complexity that you need to grok when the equations start to get complicated.

    • digitalsankhara 10 months ago

      I am old. And fashioned. "a b * c +" rules! :-)

  • dunefox 10 months ago

    ... because it's a lisp?

HexDecOctBin 10 months ago

What I would love to have is a Lisp which is as easy to embed (and as portable) as Lua but comes with all the niceties of Lisp like a restart-system, REPL-driven development, numeric tower, hygienic and non-hygienic macros, etc.

Unfortunately, no such thing seems to exist.

  • ristos 10 months ago

    Chibi scheme has almost all of those things, except non-hygienic macros: https://synthcode.com/scheme/chibi/

    It's R7RS scheme, which is a very small, well designed core for lisp. 13k LOCs of C. Very easy to embed, and a nice C FFI. I absolutely love it.

    Geiser supports Chibi scheme out of the box, and I wrote this simple nREPL for it that I use: https://github.com/Risto-Stevcev/chibi-repl-server/

    I use delimited continuations for conditions and restarts: https://gist.github.com/Risto-Stevcev/e6fd8417e34ef74a74adfa...

    • HexDecOctBin 10 months ago

      Chibi seems to rely on Cygwin/MSYS for Windows which is a pretty heavy dependency (and very non-Lua). https://github.com/ashinn/chibi-scheme/blob/master/README-wi...

      • ristos 10 months ago

        I think the posix stuff is only if you're using some of chibi's batteries-included libraries, like filesystem, regexp, shell, tar, zlib. You can probably pretty easily just stub all those files or remove them from the make build and it should build fine. The r7rs core code and libraries don't rely on anything posix related.

        • HexDecOctBin 10 months ago

          I see, thanks! Will take a look at it.

  • c-cube 10 months ago

    I don't think it has absolutely all that, but janet might be close?

    https://janet-lang.org/ https://janet.guide/

    • rcarmo 10 months ago

      Janet is nice, but the ecosystem is too small. I’ve actually uninstalled it from my Macs recently because I ended up not using it, whereas I can take any C and Lua library and do something with Fennel.

      The only real issue with Fennel is luarocks—the experience of adding new libraries (or general dependency management) to a (Lua) project is still gnarly.

    • HexDecOctBin 10 months ago

      Janet has a way to break into REPL, but AFAIK no way to restart (a la condition system).

      Fennel has something a bit more robust (assert-repl) and it can restart, but can only return a single value from the REPL, which often creates more errors downstream.

      • giraffe_lady 10 months ago

        It's been a couple years but I think janet has the primitives for this in the netrepl module which I think is part of the standard library. I remember being really surprised at how much introspection and control over the env when you responded to a repl connection, just at that time no one had put it together into what you want. I also seem to remember the actual janet repl being a different implementation which always seemed weird to me.

        • HexDecOctBin 10 months ago

          Any reference for this? The docs[1] don't seem to have much of anything.

          [1]: https://janet-lang.org/api/spork/netrepl.html

          • giraffe_lady 10 months ago

            Yeah that standard lib extension has always been extremely underdocumented.

            I thought I remembered being able to manipulate the env as a dynamic which I think could get you what you need. But reading the source now I guess not? I'm pretty out of practice reading janet.

    • ulbu 10 months ago

      it has the opposite of the numeric tower – numbers are floats. (ugh)

  • eadmund 10 months ago

    There’s Embeddable Common Lisp: https://ecl.common-lisp.dev/

    Most recent release was May of this year. I don’t know if it is as portable as Lua, but it should basically run anywhere you can call into C.

    You’d have to import a third-party hygienic CL macro system, though. But in return you get a full-fledged Lisp.

    • HexDecOctBin 10 months ago

      I believe ECL uses global state, which makes the interpreter non-reentrant, which in turn makes running multiple scripts extremely difficult (one would need to add a GIL).

  • Zambyte 10 months ago

    Maybe GNU Guile?

    • whartung 10 months ago

      You’d think Guile would work. That sounds like a Guile checklist to be honest.

      But that said, my random forays into Guile have been met with frustration. I can’t say anything specific, but for whatever reason, whenever I tried to use it, I’d get no momentum on my little project du jour, and I’d shelve it once again, moving on to something else.

      Perhaps next time it’ll click.

    • rcarmo 10 months ago

      JITed Guile is interesting, but Guile itself seems to live in a weird superposition state—it’s been around forever but there aren’t a lot of projects actually using it, so you’re stuck trying to figure out the best ways to, say, serve HTTP or set headers on requests.

    • HexDecOctBin 10 months ago

      I am a bit biased against GNU libraries. Maybe irrationally so, but I haven't had a good experience with them all the way down from Glibc. They have a tendency to be developer-hostile in very high-handed ways (sort of how GNOME treats its users). I wonder how many people still remember this piece of code:

          __asm__(".symver memcpy,memcpy@GLIBC_2.2.5");
      
      Plus, the LGPL license will ensure that it can't be shipped on a multitude of platforms (iOS I believe, game consoles, etc.)
      • hatefulmoron 10 months ago

        > Plus, the LGPL license will ensure that it can't be shipped on a multitude of platforms (iOS I believe, game consoles, etc.)

        Just for my understanding, is this based on the fact that these platforms don't allow the user to modify or upgrade Guile to another version in the future?

        • HexDecOctBin 10 months ago

          I believe that iOS simply didn't allow any LGPL code on App Store, though I don't remember the exact reasoning.

          • hatefulmoron 10 months ago

            (This is just from my very quick searching, so please correct me if I'm wrong.)

            I don't think there's any restrictions on LGPL code for the App Store, but the restrictions I mentioned earlier are probably tricky to conform to[1].

            [1]: https://stackoverflow.com/questions/35068054/does-app-store-...

            • HexDecOctBin 10 months ago

              Yeah, seems like even VLC is there. I remember that there used to be some issue with FSF licenses on the App Store, but it's been almost a decade, so I can't recall the details. I do remember switching out OpenAL-soft due to this issue.

    • AHTERIX5000 10 months ago

      Last time I checked Guile it was somewhat hard to get working on Windows, build tooling was a classic autotools mess compared to Lua consisting of a few ANSI compatible C files.

      Also Guile (and many other embeddable scripting languages) want to initialize global state which I'd prefer not to.

port19 10 months ago

Great website