std.traits.ParameterDefaults implementation
Adam D. Ruppe
destructionator at gmail.com
Mon Apr 8 18:57:59 UTC 2019
I'm looking further into some pains with parameter default
reflection and I feel Phobos' overcomplicated implementation is
to blame for the troubles and am trying to figure why it is that
way.
First, let me paste some code:
----
class C {
override @safe string toString() const { return "C"; }
}
class A {
void foo(lazy scope inout C a = new inout(C)) {}
}
@safe void main() {
import std.stdio;
foreach(overload; __traits(getOverloads, A, "foo")) {
static if(is(typeof(overload) Params == __parameters))
static foreach(idx, _; Params) {{
alias param = Params[idx .. idx + 1];
writeln("\t", __traits(identifier, param),
" = ",
function(param p) { return p[0]; }().toString
);
}}
}
}
---
This is my testbed for default argument without Phobos. And this
line is all there really is to it:
function(param p) { return p[0]; }()
I'm building with dmd -dip25 -dip1000 in an attempt to break it
with attributes. (the explicit toString on the outside is because
writeln didn't like the const class being passed to it)
On the other hand, this is Phobos' implementation:
---
template Get(size_t i)
{
// `PT[i .. i+1]` declares a parameter with an
arbitrary name.
// To avoid a name clash, generate local names that
are distinct
// from the parameter name, and mix them in.
enum name = param_names[i];
enum args = "args" ~ (name == "args" ? "_" : "");
enum val = "val" ~ (name == "val" ? "_" : "");
enum ptr = "ptr" ~ (name == "ptr" ? "_" : "");
mixin("
// workaround scope escape check, see
// https://issues.dlang.org/show_bug.cgi?id=16582
// should use return scope once available
enum get = (PT[i .. i+1] " ~ args ~ ") @trusted
{
// If the parameter is lazy, we force it to
be evaluated
// like this.
auto " ~ val ~ " = " ~ args ~ "[0];
auto " ~ ptr ~ " = &" ~ val ~ ";
// workaround Bugzilla 16582
return *" ~ ptr ~ ";
};
");
static if (is(typeof(get())))
enum Get = get();
---
It handles a missing default too, but that's trivial, just the
is(typeof()) check.
What gets me here is the function body. In mine, I just defined
an inline function and returned the parameter.
Phobos uses what appears to be a gratuitous mixin and defines two
local variables inside the function. These cause trouble with
inout
writeln(ParameterDefaults!(A.foo)[0].toString);
/home/me/d/dmd2/linux/bin32/../../src/phobos/std/traits.d(1492):
Error: variable `std.traits.ParameterDefaults!(foo).Get!0u.Get`
only parameters or stack based variables can be inout
/home/me/d/dmd2/linux/bin32/../../src/phobos/std/traits.d(1512):
Error: template instance
`std.traits.ParameterDefaults!(foo).Get!0u` error instantiating
I've seen people blame inout for this before... but it seems to
me to be that Phobos has an overcomplicated implementation.
Looking at bug 16582 which introduced the new code
https://issues.dlang.org/show_bug.cgi?id=16582
the test case is similar to what I just wrote, and my simple code
works. The other stuff in there talks about lazy. Mine worked
with that too.
Is the Phobos implementation just working around compiler bugs
that have since been fixed? Or am I missing something else in
there?
More information about the Digitalmars-d
mailing list