www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 15591] New: order of base interface list affects semantics

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

          Issue ID: 15591
           Summary: order of base interface list affects semantics
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Windows
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: r.97all gmail.com

In the code below, interface P inherits three interfaces BP, AP, NP.
The order of these interfaces changes the program behavior.
Which is, or should be, the correct one?

* compilation error
* infinite recursion
* my expectation


import std.stdio;
void main()
{
    BP c = new C(new CAP, new CNP);
    c.p(new A); // expected: output "a"
    c.p(new N); // expected: output "n"
}

/// A base class and two derived classes.
abstract class B
{
    abstract void a(P p);
}
/// ditto
class A : B
{
    override void a(P p)
    {
        /* Since typeof (this) is A here,
        the programmer expects the better match
        p.AP.p to be called. */
        p.p(this);
    }
}
/// ditto
class N : B
{
    override void a(P p)
    {
        /* Since typeof (this) is N here,
        the programmer expects the better match
        p.NP.p to be called. */
        p.p(this);
    }
}

/// interfaces which can process a data of B, A and N.
interface BP{void p(B);}
/// ditto
interface AP{void p(A);}
/// ditto
interface NP{void p(N);}

/// trivial implementations fon AP and NP.
class CAP : AP{void p(A a){"a".writeln;}}
/// ditto
class CNP : NP{void p(N n){"n".writeln;}}

/** The order of interfaces does matter, is this intended behavior?

Case:
`P : AP, BP, NP` does not compile with Error: function AP.p(A) is not callable
using argument types (N).

Case:
`P : BP, AP, NP` does compile, but to infinite recursion: A.a(P) and N.a(P)
calls NP.p(B).
*/
interface P : BP, AP, NP
{}

/// Implement AP and NP by delegation, and BP by calling the method a.
class C : P
{
    this (AP ap, NP np)
    {
        this.ap = ap;
        this.np = np;
    }
    void p(B b)
    {
        b.a(this); // forwards to either A.a or N.a, since B.a is abstract.
    }
    AP ap;
    void p(A a)
    {
        ap.p(a);
    }
    NP np;
    void p(N n)
    {
        np.p(n);
    }
}

--
Jan 22