Thread overview
opBinary : Static ifs or specialization?
Jun 23, 2020
claptrap
Jun 24, 2020
Meta
Jun 24, 2020
H. S. Teoh
Jun 24, 2020
claptrap
June 23, 2020
So you have opBinary and half a dozen operators to implement. Do you use a separate method for each operator or do you have one method and a big static if else if to select code path?

I assume they are functionally equivalent? So its just about style?
June 24, 2020
On Tuesday, 23 June 2020 at 23:53:36 UTC, claptrap wrote:
> So you have opBinary and half a dozen operators to implement. Do you use a separate method for each operator or do you have one method and a big static if else if to select code path?
>
> I assume they are functionally equivalent? So its just about style?

An idiomatic example:

import std.algorithm: among;

struct Test
{
    int payload;

    Test opBinary(string op)(Test other)
    if (op.among!("+", "-", "*", "/")) //Limit supported ops
    {
        mixin("return Test(payload " ~ op ~ "other.val);");
    }

    int opBinary(string op)(int n)
    //No constraint; support the full range of integer operations
    {
        mixin("return payload " ~ op ~ "n;");
    }
}
June 23, 2020
On Tue, Jun 23, 2020 at 11:53:36PM +0000, claptrap via Digitalmars-d-learn wrote:
> So you have opBinary and half a dozen operators to implement. Do you use a separate method for each operator or do you have one method and a big static if else if to select code path?
[...]

If your implementations are based on built-in operators, you could use mixins to unify the implementations into one, e.g.:

	struct MyInt {
		int i;
		MyInt opBinary(string op)(MyInt arg) {
			return MyInt(mixin("i "~op~" arg.i"));
		}
	}

which has far less boilerplate than separately implementing each operator.  This is one of the main reasons for the design of .opBinary.


T

-- 
Let's eat some disquits while we format the biskettes.
June 24, 2020
On Wednesday, 24 June 2020 at 00:53:58 UTC, H. S. Teoh wrote:
> On Tue, Jun 23, 2020 at 11:53:36PM +0000, claptrap via
>>
>
> If your implementations are based on built-in operators, you could use mixins to unify the implementations into one, e.g.:

Ah yeah thats useful, to expand a bit what about if the RHS is a different type?


Point!T opBinary(string op, RHS)(RHS rhs)
{
    static if (is(RHS == Point!float) || is(RHS == Point!double))
    {
        // .. etc..
    }
    else static if (is(RHS == float) || is(RHS == double))
    {
        // etc...
    }
    else static if (is(RHS == float[2]) || is(RHS == double[2]))
    {
        // .. etc...
    }
    assert(0); // type not supported
}

should that be split up?


June 24, 2020
On Wednesday, 24 June 2020 at 09:01:28 UTC, claptrap wrote:
> On Wednesday, 24 June 2020 at 00:53:58 UTC, H. S. Teoh wrote:
>> On Tue, Jun 23, 2020 at 11:53:36PM +0000, claptrap via
>>>
>>
>> If your implementations are based on built-in operators, you could use mixins to unify the implementations into one, e.g.:
>
> Ah yeah thats useful, to expand a bit what about if the RHS is a different type?
>
>
> Point!T opBinary(string op, RHS)(RHS rhs)
> {
>     static if (is(RHS == Point!float) || is(RHS == Point!double))
>     {
>         // .. etc..
>     }
>     else static if (is(RHS == float) || is(RHS == double))
>     {
>         // etc...
>     }
>     else static if (is(RHS == float[2]) || is(RHS == double[2]))
>     {
>         // .. etc...
>     }
>     assert(0); // type not supported
> }
>
> should that be split up?

I would say, depends on how you can implement what you need in the shortest way (with lest code-duplication). If one operator works with several types on RHS, but others don't, split the operators. If all operators work the same for same RHS type but different for different RHS types, split the types.