Difference between revisions of "Compile-time Command Pattern"
(Created article) |
|||
Line 1: | Line 1: | ||
From David Simcha's [http://www.youtube.com/watch?feature=player_detailpage&v=yMNMV9JlkcQ#t=571 D-Specific Design Patterns] talk at DConf 2013. | From David Simcha's [http://www.youtube.com/watch?feature=player_detailpage&v=yMNMV9JlkcQ#t=571 D-Specific Design Patterns] talk at DConf 2013. | ||
+ | |||
+ | == Problem: Need to store function and arguments to be invoked later == | ||
+ | Want: | ||
+ | * Variadic argument list | ||
+ | * Inlineability | ||
+ | * Return type polymorphism | ||
+ | * Ability to store uninstantiated function templates | ||
+ | * Minimal boilerplate | ||
+ | |||
+ | == Solution: Tempate <code>alias</code> + variadic templates == | ||
+ | <syntaxhighlight lang="d"> | ||
+ | struct Command(alias fun, Args...) | ||
+ | { | ||
+ | Args args_; | ||
+ | |||
+ | auto invoke() | ||
+ | { | ||
+ | return fun(args_); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // Instantiator Function | ||
+ | auto command(alias fun, Args...)(Args args) | ||
+ | { | ||
+ | return Command!(fun, Args)(args); | ||
+ | } | ||
+ | |||
+ | void main() | ||
+ | { | ||
+ | auto cmd = command!((a, b) => a * b)(3, 2); | ||
+ | assert(cmd.invoke() == 6); | ||
+ | } | ||
+ | |||
+ | </syntaxhighlight> | ||
+ | |||
+ | <code>Command</code> struct takes an <code>alias</code> for the function and a set of variadic arguments. An alias can be any compile-time symbol including an uninstantiated template. | ||
+ | |||
+ | The <code>invoke</code> function is not virtual because you can't have virtual functions in structs in D, so it's inlinable, and it simply forwards to the function that's passed in at compile-time as an alias with the arguments. | ||
+ | |||
+ | Since everything is bound at compile-time, <code>invoke</code> is inlinable and the function it forwards to in inlineable, there should be no overhead. | ||
+ | |||
+ | An [[Instantiator_Function_Pattern | instantiator function]] is used to avoid explicitly specifying all the arguments when instantiating <code>cmd</cmd>. | ||
+ | |||
+ | A lambda function that multiplies two numbers together is used as an example. This is actually a template literal because the types of <code>a</code> and <code>b</code> are not specified. |
Revision as of 06:31, 1 March 2014
From David Simcha's D-Specific Design Patterns talk at DConf 2013.
Problem: Need to store function and arguments to be invoked later
Want:
- Variadic argument list
- Inlineability
- Return type polymorphism
- Ability to store uninstantiated function templates
- Minimal boilerplate
Solution: Tempate alias
+ variadic templates
struct Command(alias fun, Args...)
{
Args args_;
auto invoke()
{
return fun(args_);
}
}
// Instantiator Function
auto command(alias fun, Args...)(Args args)
{
return Command!(fun, Args)(args);
}
void main()
{
auto cmd = command!((a, b) => a * b)(3, 2);
assert(cmd.invoke() == 6);
}
Command
struct takes an alias
for the function and a set of variadic arguments. An alias can be any compile-time symbol including an uninstantiated template.
The invoke
function is not virtual because you can't have virtual functions in structs in D, so it's inlinable, and it simply forwards to the function that's passed in at compile-time as an alias with the arguments.
Since everything is bound at compile-time, invoke
is inlinable and the function it forwards to in inlineable, there should be no overhead.
An instantiator function is used to avoid explicitly specifying all the arguments when instantiating cmd</cmd>.
A lambda function that multiplies two numbers together is used as an example. This is actually a template literal because the types of
a
and b
are not specified.