Downs will reply with a horrid hack involving overloading opAssign for some
static instances of some structures and then getting their values in the
function, but then you're severely limited since the "parameter" names are
globals, and since that's so, you can't have two functions that use the same
named parameters executing at the same time, either in a multithreaded
fashion or with simple recursion.
There's no general purpose way to do it, no.

Downs will reply with a horrid hack involving overloading opAssign for some
static instances of some structures and then getting their values in the
function, but then you're severely limited since the "parameter" names are
globals, and since that's so, you can't have two functions that use the same
named parameters executing at the same time, either in a multithreaded
fashion or with simple recursion.

Such abject nonsense. My hack is based on typesystem abuse, not global
*variables*.
It also doesn't use structs.
Basically, the idea is that you typedef double y_parameter; then y_parameter
y_p(double d) { return cast(y_parameter) d; }
Then just make f a templated function, so that void f(T...)(int x, T t); and
check for the presence of a y_parameter in T.
Called like so: f(2, y_p = 5f);

Such abject nonsense. My hack is based on typesystem abuse, not global
*variables*

Your face is abject nonsense!

It also doesn't use structs.
Basically, the idea is that you typedef double y_parameter; then
y_parameter y_p(double d) { return cast(y_parameter) d; }
Then just make f a templated function, so that void f(T...)(int x, T t);
and check for the presence of a y_parameter in T.
Called like so: f(2, y_p = 5f);

Such abject nonsense. My hack is based on typesystem abuse, not global
*variables*

Your face is abject nonsense!

Verily, I believe it is indeed your maternal parent who possesses this
attribute!
Ooooh, incinerate.

It also doesn't use structs.
Basically, the idea is that you typedef double y_parameter; then
y_parameter y_p(double d) { return cast(y_parameter) d; }
Then just make f a templated function, so that void f(T...)(int x, T t);
and check for the presence of a y_parameter in T.
Called like so: f(2, y_p = 5f);

If you have a lot of arguments with various optional arguments that each
have their own defaults, I think a struct is the most straightforward
solution right now.
struct FOptions {
double y = 2.0;
int z = 3;
}
void f(int x, FOptions opt) {...}
{FOptions opt;
opt.z = 10;
opt.y = 5.1;
f(1, opt);
}
{FOptions opt;
opt.z = 10;
f(1, opt);
}
It would be a lot nicer if static struct initializers worked for
non-static structs too. Then you could do:
Foptions opt = {z:10};
f(1,opt);
Or even f(1,{z:10});
There have been proposals to make struct initializers more useful along
these lines. The next step logical step in that evolution would be to
recognize a trailing struct argument as a keyword set, and let you call
f(1,z:10)
as a shortcut for
f(1,{z:10})
which would be a shortcut for something like
f(1,cast(FOptions){z:10})
which would work if struct initializers didn't have to be static.
Walter doesn't seem particularly interested, though.
--bb