New nix builtins search

https://mipmip.github.io/nix-builtins-search/
It’s WIP, but maybe useful.

14 Likes

How does it compare to https://noogle.dev/ ? I am still looking for a search which also knows about the more obscure builtins, like the unsafe ones

8 Likes

I would recommend against using builtins directly. Instead use the Nixpkgs lib, which contains (or should contain) all the builtins, and sometimes improved versions, such as foldl', as well as “polyfills” or fallback implementations that make new builtins available on the whole range of Nix versions that Nixpkgs supports.

The builtins are hugely affected by the requirement of reproducibility. The Nix language, including its builtins is meant to be a source of stability, and we’ve been rather successful at keeping it stable. You can still evaluate decade old expressions and get the same result. This would not be the case if we changed the builtins whenever we felt like it.

Nixpkgs lib doesn’t suffer from this requirement. It can evolve, and old expressions keep working because they simply use an older lib.

And finally there’s the argument of consistency. You probably want to use lib because of some functions anyway, and it’s nicer if you don’t have to think whether some function comes from builtins or lib.

16 Likes

I actually did not know about noogle.dev. I find this great too! This builtins search was a fast POC copy of the home manager options search. If people use it, I might continue adding features and searchable content.

1 Like

Could we develop an elegant solution to get rid of those numerous builtins. and lib. prefixes?

As I remember, there have been steps towards it years ago, i.e. import was able to pass a hidden parameter to every call, akin to Scala’s implicit so a variable from the importing scope magically appears in the importing scope (it has not to be necessarily lib, but lib and lib.* are the first candidate for that), then the feature has been abandoned or even reverted.

Also, currently, builtins. (but not lib.) is the same as __, e.g. one can write __toJSON instead of builtins.toJSON, this seems so ugly so almost everybody prefers builtins..

4 Likes

This advice may be true for contributing to nixpkgs, but there is also a world outside. Some people may like to use builtins directly without introducing an additional dependency on nixpkgs.

Having this layer of abstraction is currently also not really practical because some builtins are not proxied through. But I understand and support your vision, to decouple things.

3 Likes

I recommend the same for projects other than Nixpkgs.

You can get a suitably small dependency from nix-community/nixpkgs.lib, or hopefully natively from the actual source in a couple of months, after improvements to fetchTree and the git fetcher.

I’ll be happy to review the addition of whatever is still missing from lib.

5 Likes

You can use the with lib; construct. But I guess you meant something else?

identifiers imported with lib often have naming conflicts with local variables (and the conflict resolution order is not intuitive at all), so, yes, it’s better to invent something else. But I don’t have any good ideas yet, so far I write explicitly lib. and builtins. everywhere.

3 Likes

Same. Also I read the with construct is considered an anti pattern now. So there’s that too.

1 Like

I’m pretty happy doing something along the lines of:

let
    inherit (builtins) readFile fromTOML;
    inherit (lib.lists) forEach foldl flatten remove;
    inherit (lib.attrsets) recursiveUpdate optionalAttrs mapAttrsToList;
    qw = s: lib.strings.splitString " " s;
    # ...
in

but I will keep in mind the advice about referring to builtins directly.

2 Likes

I never thought of combining inherit with let in. It looks nice.

1 Like

I would recommend against using builtins directly. Instead use the Nixpkgs lib

I would do this if there was a separate repo for lib, and if the lib didn’t include stdenv (e.g. if it was a pure).

I know I know “it’s a lazy runtime” and all, but I really dislike adding a dependency on a massive repo/tarball just to use a single tiny little helper function.

It’s an anti-pattern because with lib is awful for the new-to-nix dev, and the performance of the nix runtime. Especially because doing with lib at the top makes it really likely for nested with’s, and it’s literally impossible to do static code analysis on nested withs (for humans or editor tooling). We have to run the code to even know where the var comes from.

A new dev seeing builtin.map on Github knows exactly what to Google when they don’t understand the arguments.

But seeing a map inside of a with lib; with pkgs; with thisPkgUtils;, becomes a massive undertaking to know which attrSet it came from, find its implementation, or even just know what-to-search to figure out what the arguments mean.

1 Like

I had the same conclusion about discoverability. It’s the same deal in Haskell. But I had never thought about performance penalty, although it makes sense too.

1 Like

Also fun fact, Javascript used to have a similar with statement. According to MDN it “makes optimization impossible” among other issues, and AFAIK out of all the bad behavior in JS it’s the only keyword that’s ever been removed.

GitHub - nix-community/nixpkgs.lib: nixpkgs lib for cheap instantiation [maintainer=@github-action] (with initial help from @blaggacao) might be relevant to your interests.

2 Likes

As a lib maintainer I’d be totally on-board to have a separate repo for it!

3 Likes

This is awesome thank you! I will definitely use this. Even if its not all the way pure its a big upgrade.

this is going a bit offtopic but what is currently stoping us?