www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 15300] New: Better support for operator overloading in

https://issues.dlang.org/show_bug.cgi?id=15300

          Issue ID: 15300
           Summary: Better support for operator overloading in
                    std.variant.Algebraic
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: phobos
          Assignee: nobody puremagic.com
          Reporter: tobias pankrath.net

Code
---
import std.algorithm, std.container;
import std.variant, std.stdio;

alias Doc = Algebraic!(P, Q);

struct Q
{
    Q opBinary(string s)(const Q rhs)
    {
        P result;
        result.curColumn = this.curColumn + rhs.curColumn;
        return result;
    }
    int curColumn = 0;
}

struct P
{
    P opBinary(string s)(const Doc rhs)
    {
        P result;
        return result;
    }

    P opBinary(string s)(const P rhs)
    {
        P result;
        result.curColumn = this.curColumn + rhs.curColumn;
        return result;
    }
    int curColumn = 0;
}

void main()
{
    auto a = Doc(P(2));
    auto b = P(3);      // works (1)
    auto c = Doc(P(3)); // runtime failure (2)
    auto d = a + b;
    writeln(d);

}
---

Currently you can use operators/operator overloading with
std.variant.Algebraic, if 
   * the operand is a buildin arithmetic datatype like int
   * both operands have the same type

But not if the operand is the algebraic datatype itself. This could be
improved.

(A) In case (2) if P does have an opBinary overload for Doc, it should use it. 

(B) If there is no specific overload, it should try to do some kind of double
dispatch on the types:

Algebraic!(A,B,C) opBinary(string op)(const Algebraic!(A,B,C) rhs)
{
   return this.visit!(
   (A lhsA) { return rhs.visit!(
     (A rhsA) { return DoOrFail!op(lhsA, rhsA); },
     (B rhsB) { return DoOrFail!op(lhsA, rhsB); }, (...)
   (B lhsB) { return rhs.visit!(
      (A rhsA) { return DoOrFail!op(lhsB, rhsA); },
      (B rhsB) { return DoOrFail!op(lhsB, rhsB); }, (...)
   );
}

Where DoOrFail is

Algebraic!(A,B,C) DoOrFail(L,R, string op)(L l, R r)
{
  static if(__compiles(l.opBinary!(op)(r)))
     return Algebraic!(A, B, C)( l op r)
  else
     throw VariantError ...
}


(A) is especially useful with self referential types.

--
Nov 08 2015