Difference between revisions of "Mixin Macros Pattern"

From D Wiki
Jump to: navigation, search
(Solution: Mixins + Compile-Time Magic: - Added explanation)
m (Solution: Mixins + Compile-Time Magic: - wordsmithing)
Line 35: Line 35:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
The way D's operating overloading works, is there's only one function you need to overload that supports all the binary operators, as opposed to the C++ where each operator is it's own individual implementation.  It takes a string that represents its operator as a template parameter.  So, for the addition operator, the <code>opBinary</code> template will be instantiated with the "+" string, and for the subtraction operator, it will instantiated with the "-" string. The beauty of this is it enables reduction of boilerplate code, with one mixin macro handling all binary operators.  
+
The way D's operating overloading works, is there's only one function to overload for all binary operators, as opposed to the C++ where each operator is it's own individual implementation.  The function takes a string, that represents its operator, as a template parameter.  For example, to implement the addition operator, the <code>opBinary</code> template will be instantiated with the "+" string, and to implement the subtraction operator, it will instantiated with the "-" string. The beauty of this is it enables reduction of boilerplate code with one mixin macro handling all binary operators.  
  
 
In the example above, the lhs value (<code>value_</code>), the operator string (<code>op</code>), and the rhs value (<code>rhs.value_</code>) are appended to one another and then mixed in. When mixed in, the resulting string is evaluated at the current scope as regular code.  In the example above it would be prudent to add a template constraint to verify that the operator is either a "+" or a "-" since those are the only implementations.  It doesn't have the performance cost of runtime evaluation, and unless the build system is compromised there's no security risk since it's all evaluated at compile-time.  It's using compile-time computations to essentially create macros.
 
In the example above, the lhs value (<code>value_</code>), the operator string (<code>op</code>), and the rhs value (<code>rhs.value_</code>) are appended to one another and then mixed in. When mixed in, the resulting string is evaluated at the current scope as regular code.  In the example above it would be prudent to add a template constraint to verify that the operator is either a "+" or a "-" since those are the only implementations.  It doesn't have the performance cost of runtime evaluation, and unless the build system is compromised there's no security risk since it's all evaluated at compile-time.  It's using compile-time computations to essentially create macros.

Revision as of 04:26, 9 November 2014

From David Simcha's D-Specific Design Patterns talk at DConf 2013.

Problem: Repetitive code with slight variations

Example: Arithmetic operator overloading

Want:

  • Minimal code duplication
  • Ability to use templates/CTFE
  • (Avoid (Lispy (syntax)))

Solution: Mixins + Compile-Time Magic

// D's operator overloading was designed around mixins
struct Int 
{
    Int opBinary(string op)(Int rhs)
    {
       int value = mixin("value_ " ~ op ~ " rhs.value_");
       return Int(value);
    }

    int value() @property 
    { 
        return value_; 
    }

    private int value_;
}

void main()
{
    assert((Int(2) - Int(5)).value == -3);
    assert((Int(2) + Int(4)).value == 7);
}

The way D's operating overloading works, is there's only one function to overload for all binary operators, as opposed to the C++ where each operator is it's own individual implementation. The function takes a string, that represents its operator, as a template parameter. For example, to implement the addition operator, the opBinary template will be instantiated with the "+" string, and to implement the subtraction operator, it will instantiated with the "-" string. The beauty of this is it enables reduction of boilerplate code with one mixin macro handling all binary operators.

In the example above, the lhs value (value_), the operator string (op), and the rhs value (rhs.value_) are appended to one another and then mixed in. When mixed in, the resulting string is evaluated at the current scope as regular code. In the example above it would be prudent to add a template constraint to verify that the operator is either a "+" or a "-" since those are the only implementations. It doesn't have the performance cost of runtime evaluation, and unless the build system is compromised there's no security risk since it's all evaluated at compile-time. It's using compile-time computations to essentially create macros.