www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - covariance, operator overloads, and interfaces

reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
The situation with interfaces and operators is getting worse and worse as  
I try to implement it.

Here is another issue I have found.

Previously in dcollections, I support the ~ operator on Lists.

The relevant interface looked something like this:

interface List
{
    List opCat(List rhs);
}

So something like an array list would use covariance to make the syntax  
sugar more pleasant:

class ArrayList : List
{
    ArrayList opCat(List rhs);
}

Now, you can do things like this:

ArrayList al, al2;

al = al ~ al2;

Fine and dandy.  However, with the new operator overloading scheme, I must  
define the operator as follows:

interface List
{
    List concat(List rhs);
    List opBinary(string op)(List rhs) if (op == "~")
    {
        return concat(rhs);
    }
}

But now I lose covariance, the above usage no longer compiles.

I don't know how to solve this without dropping interfaces, or repeating  
the template in all derived classes.

-Steve
May 11 2010
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 11 May 2010 09:33:38 -0400, Steven Schveighoffer  
<schveiguy yahoo.com> wrote:


 I don't know how to solve this without dropping interfaces, or repeating  
 the template in all derived classes.
Here's an idea. What if when using an auto return on a template, it becomes automatically covariant for derived classes? For example: interface List { List append(List l); auto opOpAssign(string op : "~=")(List rhs) { return append(l); } } class ArrayList : List { ArrayList append(List l); } ArrayList al = new ArrayList; ArrayList al2 = new ArrayList; auto x = (al ~= al2); when compiling the above line, the compiler should recognize that the template returns auto. It does the calculation of what type to return based on the context. In the context of ArrayList, append returns ArrayList, so opOpAssign should return ArrayList. Problems may arise if the compiler can easily determine the result when dealing with straight interfaces, but cannot easily determine when dealing with derived classes. I think in those cases, the compiler should just output an error, and the user will be forced to concretely specify the return type, or fix their method to be more covariant-friendly. How does this sound? I'd also like to see this for final interface functions as well. -Steve
May 11 2010
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-05-11 09:33:38 -0400, "Steven Schveighoffer" 
<schveiguy yahoo.com> said:

 interface List
 {
     List concat(List rhs);
     List opBinary(string op)(List rhs) if (op == "~")
     {
         return concat(rhs);
     }
 }
 
 But now I lose covariance, the above usage no longer compiles.
 
 I don't know how to solve this without dropping interfaces, or 
 repeating  the template in all derived classes.
Can't you repeat the opBinary template in the ArrayList class with a covariant return? class ArrayList : List { ArrayList concat(List rhs); ArrayList opBinary(string op)(List rhs) if (op == "~") { return concat(rhs); } } Not very elegant, but I think it'll work. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
May 11 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Michel Fortin wrote:
 On 2010-05-11 09:33:38 -0400, "Steven Schveighoffer" 
 <schveiguy yahoo.com> said:
 
 interface List
 {
     List concat(List rhs);
     List opBinary(string op)(List rhs) if (op == "~")
     {
         return concat(rhs);
     }
 }

 But now I lose covariance, the above usage no longer compiles.

 I don't know how to solve this without dropping interfaces, or 
 repeating  the template in all derived classes.
Can't you repeat the opBinary template in the ArrayList class with a covariant return? class ArrayList : List { ArrayList concat(List rhs); ArrayList opBinary(string op)(List rhs) if (op == "~") { return concat(rhs); } } Not very elegant, but I think it'll work.
He already mentioned "repeating the template in all derived classes". This is another place in which we need typeof(class) to yield the class being currently compiled. Andrei
May 11 2010