mthdr About

Why I Like Janet

What I Look For In A Language

Powerful Macros

Most of the time you don't need macros, but in my experience when you need them and you don't have them, you suffer. Like most lisps, Janet has great support for macros. There is a flaw where naively writing DSLs will not produce great error messages, but this is something that I'm confident can be fixed with just a small library.

Out-of-the-box Ergonomics

A language should be pleasant and easy to use out-of-the-box. It's important that this be out-of-the-box. If a language can be made ergonomic, but it requires fiddling with tooling and a bunch of libraries, then that's not good for many use cases like short scripts, and it's more brittle since libraries and tooling tend to come and go much faster than languages do.

Janet fulfills this the best out of any lisp I've ever tried. Most lisps give long function names for extremely common things like accessing elements of a data structure, creating anonymous functions, defining values, and so on. This makes them cumbersome to code in. I am pleased to say that Janet is not like that.


Odds are that you can't build everything in just your favorite language, so it's important to have a good foreign function interface. This interface should go both ways: it should make it easy to call foreign functions from inside our language, and easy to call our language from other outside languages.

Language To Build Languages

I'm the type to be suckered in by the beauty of Racket's "language to build languages" philosophy. However, there are two flaws in Racket's approach, which I hinted at in the previous section.

The first is out-of-the-box ergonomics, which Racket does much less well than Janet. I used Racket to write a script once, then immediately went back to Ruby. But I haven't touched Ruby except for maintaining old scripts since I learned Janet.

The second is the runtime. There are many languages whose appeal is in their runtime. Some languages appeal by having very small/nonexistant runtimes and being very fast, like C and Rust. Others by having runtimes with nice properties, like Erlang. If your language to build languages is stuck in one heavy runtime, then there are some languages that you just can't usefully build.

For this reason, it's important that a language to build languages have a small runtime, good FFI, and be embeddable, and this is where Janet shines. You can build a DSL in Janet to generate C code that interfaces with Janet, effectively allowing you to code everything in Janet.

One disadvantage of Janet is the lack of syntax objects, which are important for good error reporting in DSLs. However, barring unforseen complications, Janet is flexible that I'm pretty sure these can be added as a library with some work.

It won't be as convenient as having them out-of-the-box like in Racket. Thankfully you usually only need complex DSLs for larger projects where you're probably already bringing in other dependencies, so it's less of a disadvantage in this case.

Where To Learn Janet

Since I'm writing a post about Janet, I should mention where to go to learn more about it. I suggest this very good book about Janet by Ian Henry.