nix coercion trick

Published 2020-09-02 on Farid Zakaria's Blog

tl;dr; If the attrset contains outPath, it can automatically be converted to a String.

The Nix expression language is somewhat documented. I came across the following links:


Nix is a strongly typed language although it is lazily typed. The fact that it is strongly typed means that certain type coercion are not feasible.

nix-repl> (1 + "Hello")
error: cannot add a string to an integer, at (string):1:2

However while playing around with niv; I noticed that the attribute sets could automatically be converted to strings.

nix-repl> sources = import ./nix/sources.nix

nix-repl> :p sources.nixpkgs
{ branch = "nixpkgs-unstable"; description = "Nix Packages collection"; homepage = null; outPath = "/nix/store/shayf8qxmb7aqgzncvz1abnar7s2cssa-nixpkgs-src"; owner = "NixOS"; repo = "nixpkgs"; rev = "f9567594d5af2926a9d5b96ae3bada707280bec6"; sha256 = "0vr2di6z31c5ng73f0cxj7rj9vqvlvx3wpqdmzl0bx3yl3wr39y6"; type = "tarball"; url = ""; url_template = "<owner>/<repo>/archive/<rev>.tar.gz"; }

nix-repl> builtins.typeOf sources.nixpkgs

nix-repl> "${sources.nixpkgs}"

How is this possible?

After a very helpful post by danieldk; the answer was found!

Please checkout for relevant source.

if (v.type == tAttrs) {
    auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore);
    if (maybeString) {
        return *maybeString;
    auto i = v.attrs->find(sOutPath);
    if (i == v.attrs->end()) throwTypeError(pos, "cannot coerce a set to a string");
    return coerceToString(pos, *i->value, context, coerceMore, copyToStore);

If the set contains *outPath; then the set can be coerced into a string!

nix-repl> set = { outPath="Hello World"; }

nix-repl> "${set}"
"Hello World"