Difference between revisions of "Compile-time Command Pattern"

From D Wiki
Jump to: navigation, search
(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.