Placeholder vs builtins.placeholder in nixpkgs

Just some idle curiosity:

git grep '{builtins.placeholder "out"' | wc -l
44
git grep '{placeholder "out"' | wc -l
1878

Is there a reason why plain placeholder seems to be strongly preferred, and how is it brought into scope automagically?

Followup question: should this be made consistent throughout nixpkgs? The number of required changes seem manageable (when moving towards plain placeholder).

1 Like

They’re identical (that is, placeholder is just another name for builtins.placeholder).

There are a few other builtins like this, but funnily enough, the documentation on the matter is incorrect! (Built-ins - Nix 2.30.3 Reference Manual)

I’ll likely go digging at some point this week and fix the docs. :slight_smile:

2 Likes

They’re the same thing.

nix-repl> placeholder
«primop placeholder»

nix-repl> builtins.placeholder
«primop placeholder»

Less keys to press?

And it’s nix’s fault/business/whatever that placeholder is available outside of the builtins scope. Probably because the function is really commonly useful and unlikely (?) to collide.

I don’t think it’s worth the time to create or review the PR.
We have more productive treewides that could be run IMO.

Actually after checking the code, looks like practically all the builtins are exposed globally

313:        .name = "scopedImport", .arity = 2, .fun = [](EvalState & state, const PosIdx pos, Value ** args, Value & v) {
318:    {.name = "import",
525:    .name = "__typeOf",
543:    .name = "isNull",
561:    .name = "__isFunction",
577:    .name = "__isInt",
593:    .name = "__isFloat",
609:    .name = "__isString",
625:    .name = "__isBool",
641:    .name = "__isPath",
808:        .name = "__genericClosure",
865:    {.name = "break",
888:    {.name = "abort",
904:    {.name = "throw",
944:        .name = "__addErrorContext",
990:    .name = "__ceil",
1045:    .name = "__floor",
1095:    .name = "__tryEval",
1127:    .name = "__getEnv",
1152:    .name = "__seq",
1171:    .name = "__deepSeq",
1198:    .name = "__trace",
1244:    .name = "__warn",
1773:        .name = "derivationStrict",
1792:    .name = "placeholder",
1821:    .name = "__toPath",
1864:    .name = "__storePath",
1905:    .name = "__pathExists",
1946:    .name = "baseNameOf",
1982:    .name = "dirOf",
2023:    .name = "__readFile",
2088:        .name = "__findFile",
2236:    .name = "__hashFile",
2288:    .name = "__readFileType",
2338:    .name = "__readDir",
2374:    .name = "__outputOf",
2419:    .name = "__toXML",
2527:    .name = "__toJSON",
2553:    .name = "__fromJSON",
2619:    .name = "__toFile",
2781:    .name = "__filterSource",
2883:    .name = "__path",
2938:    .name = "__attrNames",
2971:    .name = "__attrValues",
2994:    .name = "__getAttr",
3020:        .name = "__unsafeGetAttrPos",
3083:    .name = "__hasAttr",
3101:    .name = "__isAttrs",
3137:    .name = "removeAttrs",
3209:    .name = "__listToAttrs",
3305:    .name = "__intersectAttrs",
3339:    .name = "__catAttrs",
3383:    .name = "__functionArgs",
3417:    .name = "__mapAttrs",
3487:    .name = "__zipAttrsWith",
3530:    .name = "__isList",
3553:    .name = "__elemAt",
3573:    .name = "__head",
3599:    .name = "__tail",
3633:    .name = "map",
3688:    .name = "__filter",
3711:    .name = "__elem",
3734:    .name = "__concatLists",
3750:    .name = "__length",
3782:    .name = "__foldl'",
3830:    .name = "__any",
3845:    .name = "__all",
3877:    .name = "__genList",
3940:    .name = "__sort",
4025:    .name = "__partition",
4077:    .name = "__groupBy",
4133:    .name = "__concatMap",
4168:    .name = "__add",
4199:    .name = "__sub",
4230:    .name = "__mul",
4263:    .name = "__div",
4279:    .name = "__bitAnd",
4296:    .name = "__bitOr",
4313:    .name = "__bitXor",
4331:    .name = "__lessThan",
4357:    .name = "toString",
4430:    .name = "__substring",
4459:    .name = "__stringLength",
4485:    .name = "__hashString",
4518:    .name = "__convertHash",
4655:    .name = "__match",
4758:    .name = "__split",
4828:    .name = "__concatStringsSep",
4903:    .name = "__replaceStrings",
4938:    .name = "__parseDrvName",
4962:    .name = "__compareVersions",
4993:    .name = "__splitVersion",
5226:            .name = "__importNative",
5231:            .name = "__exec",
5239:        .name = "__traceVerbose",

Most just happen to be prefixed with __.

nix-repl> __getEnv
«primop getEnv»

nix-repl> builtins.getEnv
«primop getEnv»

PR sent :slight_smile:

2 Likes

Thanks for the clarification and the doc update!