I have a function wrap
that wraps function fn
. fn
has arguments with defaults. I wish to avoid having to duplicate the argument defaults in wrap
. How do I go about this?
rec {
wrap = { a, d ? null }: (fn { inherit d; b = a + "-hi"; });
fn = { b, d ? null }: b + (if d = null then "-meep" else d);
}
This doesn’t work, it fails if d is not passed:
rec {
wrap = { a, ... } @ args: (fn { d = args.d; b = a + "-hi"; });
fn = { b, d ? null }: b + (if d = null then "-meep" else d);
}
One option is to write your args like
fn { ${if args?d then "d" else null} = args.d; b = a + "-hi"; }
This works reasonably well if you just need to do this for a single arg.
Another option if you’re just trying to transform one arg and leave the rest alone is to write it that way:
fn (args // { b = a + "-hi"; })
This approach doesn’t work with your example as written though as it will pass an arg a
to fn
, which isn’t declared and therefore will fail.
A third option if you need to pass along many args but can’t pass along everything is to write something using builtins.functionArgs
. In your case builtins.functionArgs fn
will return { b = false; d = true; }
, which you can intersect with args
. Something like
fn (builtins.intersectAttrs (builtins.functionArgs fn) args // { b = args.a + "-hi"; })
2 Likes
I forgot to suggest a fourth option: Where you want wrap
to take variadic arguments but you don’t want to allow any args that fn
doesn’t take, except for a
. In this case you simply remove the extra args you’re accepting from the args
set and otherwise pass it along, e.g.
wrap = { a, ... } @ args: fn (builtins.removeAttrs args [ "a" ] // { b = a + "-hi"; })
Admittedly the user can now pass b
to wrap
and it will be overwritten rather than fail, but at least they can’t pass c
:
nix-repl> wrap { a = "oh"; }
"oh-hi-meep"
nix-repl> wrap { a = "oh"; d = "-there"; }
"oh-hi-there"
nix-repl> wrap { a = "oh"; b = "ignored"; }
"oh-hi-meep"
nix-repl> wrap { a = "oh"; c = "wat"; }
error: anonymous function at (string):1:2 called with unexpected argument 'c', at (string):1:21
1 Like