Nickel: the Nix (language) spin-off

For those who attended NixCon on Saturday, I presented in a lightening talk an on-going project called Nickel. This is a configuration programming language inspired from Nix. It is still not at release stage, but if you want to learn more, there’s a fresh blog post about it, and we recently made the repo public.

Cheers

P.S: don’t mind the current ugly examples in src/examples, they are quite old and need to be rewritten once we’ve made a pass on the syntax.

8 Likes

Knew it would be in Rust even before opening the link :slight_smile:

I followed Théophane‘s work on gradually typing nix - looks like this is some follow-up?

The details may have changed a bit since Théophane’s initial report, but yes indeed, this is somehow the continuation of this approach.

Are there any examples on how one would use Nickel to create a Nix derivation? If I understand it correctly, Nix has the derivation primitive, and the Nixpkgs standard library provides a whole bunch of extra function (e.g., the mkDerivation convenience function around derivation). Would it be possible to use the stdenv functions, or would these have to be re-implemented in Nickel?

1 Like

This is a very good question, and we are exploring this at this very moment.

Currently, we are experimenting with the least invasive and simplest alternatives, that would allow you to write just one derivation or one NixOS module in Nickel, without having to implement implement stuff either in Nix (I mean, in the package manager itself) or to re-implement the Nix features you mention on the Nickel side.

For example, you could write a shell description in Nickel (shell.nickel). Then, your shell.nix calls to a generic Nix library function that runs Nickel to generate a JSON, then imports said JSON and return the corresponding shell. This is not totally as simple as it sounds and a bit hacky (just specifying buildInputs can’t be done just in JSON, so the Nix import code actually has to do some parsing to rebuild the inputs), but is done easily in a very direct way.

Another way would be to have good languages interoperability, for example being able to import nix expressions directly in Nickel and to transpile Nickel values (once evaluated) to Nix expressions. Doing so, we can still leverage everything that already exists in Nix without having to re-implement it on the Nickel side.

Lastly, the most involved ones - but maybe also the most powerful - would be to either add Nickel support directly in Nix, which would accept Nickel sources in addition to Nix expressions, or the other way around, as you described: re-implement Nix features on the Nickel side such that a Nickel file would be able to evaluate all the way down to a derivation.

9 Likes

This is super exciting and I appreciate the detailed thoughts about this. While unsurprising that thought has been put into this, it’s great to see confirmation and start to imagine.

3 Likes

Thank you for the detailed answer! By the way, when I first skimmed the introduction to Nickel and saw gradual typing mentioned, I thought that Nickel’s relationship to Nix will be akin to Typescript’s relationship to JavaScript (as in, a valid JS program is a valid TS program as well), but you already answered this as well:)

1 Like

Glad to hear that!

You’re welcome!

It’s true that most of gradually typed languages are usually a superset of an existing, dynamically typed language. However, in the case of Nickel, we chose gradual typing on its own: you can learn more about this in this blog post on Nickel’s type system.

Additionally, Nickel won’t be a strict superset of Nix, at least syntactically, for practical reasons: for example, we want to use : for type annotations as in any other language out there, but Nix uses it for function arguments.

That said, Nickel could be close to a superset of Nix, modulo syntax: parsing Nix expressions and translating them to Nickel does seem reasonable, although there’s still some aspects to figure out (Nickel currently doesn’t have string contexts, for example, neither dynamic scoping via with).

2 Likes

Just found the Figure out an adoption plan #93 issue in the Nickel repo that provides some really interesting facts. For example,

Nix already supports importing other languages, via the import-from-derivation feature. If the language can produce nix expressions in a derivation, nix will be able to import them as if they were provided to the interpreter directly (they are loaded from a store path). ()

but the entire thread is worth reading. (It also answers a couple other questions that I now don’t have to ask.)

2 Likes