argparse
argparse copied to clipboard
One does not simply pass a closure to a `LazyString`
Discovered this when I was trying to deduplicate Complete.InitCmd
. A reduced example that should be easier to follow:
struct Description {
string delegate() dg;
}
auto createCompleter(string desc) {
@Description(() => desc) // Seems good so far.
struct Complete { }
return Complete.init; // Err... We haven't stored `desc` anywhere, have we?
}
void main() {
import std.stdio: writeln;
import std.traits: getUDAs;
enum completer = createCompleter("Description.");
writeln(getUDAs!(typeof(completer), Description)[0].dg()); // Here.
}
The compiler blames: delegate test.createCompleter.__lambda3
is a nested function and cannot be accessed from D main
. And it is right. Therefore, a delegate can be used with a LazyString
only if it does not escape its declaration scope.
UDAs are attached at struct-declaration time, but variables we want to close over are only available at instance-creation time. Unfortunately, I can’t think of a good solution here. One idea comes to my mind: add a third option to LazyString
, which should be a struct with no members, to signify even more runtime strings. Then a caller can test for this and invoke cmd.getDescription
. That should work in principle, but it requires patching every callsite to account for that, which I’m not happy with. Any better ideas?