As discussed in DConf2015: Python-like keyword arguments
Jonathan Crapuchettes via Digitalmars-d
digitalmars-d at puremagic.com
Fri May 29 08:16:56 PDT 2015
Two other ways to implement the concept. The first works with optional
arguments and the other requires all arguments.
/**
* Optional arguments and no default values; might not compile if all args
* not passed.
*/
---------------------------------------------------------------------------
/**
* A templated function useful for creating aliases for naming function
* parameters.
*/
auto namedArguments(string name, T)(T arguments)
{
static struct Args
{
enum string argName = name;
T argValue;
alias argValue this;
}
return Args(cast(Unqual!T)arguments);
}
///
unittest
{
alias arg1 = namedArguments!("arg1", string);
alias arg2 = namedArguments!("arg2", int);
void namedArgsFunc(T...)(T arguments)
{
const vars = parseArguments!()(arguments);
const string one = vars.arg1;
const int two = vars.arg2;
}
namedArgsFunc(arg1(""), arg2(42));
namedArgsFunc(arg2(56), arg1("fred"));
}
private enum isNamedArgument(T) = hasMember!(T, "argName") && hasMember!
(T, "argValue");
/**
* Parse parameters of the type returned from $(D namedArguments) into a
* named tuple usable in a function.
*/
auto parseArguments(T...)(T inputs) if (allSatisfy!(isNamedArgument, T))
{
template GetTypeAndName(ArgT)
{
alias Type = typeof(ArgT.argValue);
enum string Name = ArgT.argName;
alias GetTypeAndName = TypeTuple!(Type, Name);
}
auto ret = Tuple!(staticMap!(GetTypeAndName, T))();
foreach (arg; inputs)
{
mixin(`ret.` ~ arg.argName) = arg.argValue;
}
return ret;
}
unittest
{
alias arg1 = namedArguments!("arg1", string);
alias arg2 = namedArguments!("arg2", int);
const test1 = parseArguments(arg1("string"), arg2(42));
assert(test1.arg1 == "string");
assert(test1.arg2 == 42);
const test2 = parseArguments(arg2(42), arg1("string"));
assert(test2.arg1 == "string");
assert(test2.arg2 == 42);
}
--------------------------------------------------------------------------
///All required arguments
--------------------------------------------------------------------------
/**
* A templated function useful for creating aliases for naming function
* parameters.
*
* Params:
* ArgTypesT = The enum type for all named parameters in a group.
*
* Returns: A voldemort type that can be handled by $(D parseArguments).
*/
template namedArguments(ArgTypesT) if (is(ArgTypesT == enum))
{
auto namedArguments(ArgTypesT type, T)(T arguments)
{
static struct Args
{
alias ArgType = ArgTypesT;
enum ArgType argsType = type;
T args;
alias args this;
}
return Args(cast(Unqual!T)arguments);
}
}
///
unittest
{
enum ArgTypes
{
Arg1,
Arg2
}
alias FuncArgsT = namedArguments!ArgTypes;
alias arg1 = FuncArgsT!(ArgTypes.Arg1, string);
alias arg2 = FuncArgsT!(ArgTypes.Arg2, int);
void namedArgsFunc(T...)(T arguments)
{
const vars = parseArguments(arguments);
const string one = vars.Arg1;
const int two = vars.Arg2;
}
namedArgsFunc(arg1(""), arg2(42));
namedArgsFunc(arg2(56), arg1("fred"));
}
private enum isNamedArgument(T) = hasMember!(T, "argsType") && hasMember!
(T, "args");
/**
* Parse parameters of the type returned from $(D namedArguments) into a
* named tuple usable in a function.
*/
auto parseArguments(T...)(T inputs) if (allSatisfy!(isNamedArgument, T))
{
template GetTypeAndName(ArgT)
{
import std.conv : to;
alias Type = typeof(ArgT.args);
enum string Name = ArgT.argsType.to!string();
alias GetTypeAndName = TypeTuple!(Type, Name);
}
auto ret = Tuple!(staticMap!(GetTypeAndName, T))();
foreach (I, arg; inputs)
{
ret[I] = arg.args;
}
return ret;
}
unittest
{
enum ArgTypes
{
Arg1,
Arg2
}
alias FuncArgsT = namedArguments!ArgTypes;
alias arg1 = FuncArgsT!(ArgTypes.Arg1, string);
alias arg2 = FuncArgsT!(ArgTypes.Arg2, int);
const test1 = parseArguments(arg1("string"), arg2(42));
assert(test1.Arg1 == "string");
assert(test1.Arg2 == 42);
const test2 = parseArguments(arg2(42), arg1("string"));
assert(test2.Arg1 == "string");
assert(test2.Arg2 == 42);
}
--------------------------------------------------------------------------
Jonathan
More information about the Digitalmars-d
mailing list