Alternatives to `with` expression

OCaml has a beautiful syntax which would be lovely in Nix too. First, let’s define a module, akin to doing {x = 123; y = 456; z = 789; } in Nix (the module definition isn’t the syntax I mean)

module Test = struct
    let x = 1
    let y = 2
    let z = 3
end

Then if you want to scope expressions to have the values from the module, you can do

let x = 4
let result  = Test.(x * y + z) - x

This is equivalent to doing Test.x * Test.y + Test.z - x. But you can also use them in lists, e.g.

let [1; 2; 3] = Test.[x; y; z]

So possibly something like the following could work, be nicer to static analysis tools, less confusing than with due to selecting innermost value not outermost value

let
  test = {
    x = 1;
    y = 2;
    z = 3;
  };
  x = 1 
in {
  foo = test.(x * y + z) - x;
  bar = test.[x y z];
  baz = test.{ inherit x; "key${y}" = y; };
}

I have started implementing it at WIP: Add scoped expressions inspired by OCaml by KoviRobi · Pull Request #12471 · NixOS/nix · GitHub but I’ll need to think/read how Nix works more before I can finish it. It currently just uses the normal with semantics, though syntactically it is implemented.

As with all syntax changes, it should be done carefully, so needs more tests and experimentation.

Possibly also missing things like test.''x is ${x}'' but that might be too close to test."x is ${x}" which tries to access "x is ${outer x}" in test.

Also this makes test."${x}" different from test.("${x}") which might be confusing, and merit a warning?

I also suggest looking into prior work: [RFC 0181] List index syntax by rhendric · Pull Request #181 · NixOS/rfcs · GitHub

See also my experimental implementation of a design by pennae at libexpr/nix2: Add slicing operators · Gerrit Code Review, which goes into a quite similar direction

2 Likes