www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 2050] New: interfaces should allow final methods with body

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050

           Summary: interfaces should allow final methods with body
           Product: D
           Version: unspecified
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla digitalmars.com
        ReportedBy: andrei metalanguage.com


Consider:

interface Foo
{
    void bar();
    final void baz() { bar; bar; }
}

This code doesn't go through on grounds that interfaces cannot define methods
with bodies. In fact, final methods don't break any laws of nature because they
are not meant to be overriden and, aside from lookup, have the regime of
ordinary functions.

It would appear that this issue is easy to mitigate:

interface Foo
{
    void bar();
}

void baz(Foo foo) { foo.bar; foo.bar; }

Generally I favor free functions so I'd be happy with the above. But there are
two troublesome scenarios:

1. Operators must be members

2. Sutter's NVI idiom (http://www.gotw.ca/publications/mill18.htm) can be
implemented more clearly with members than with virtual functions. There are a
couple of other bugs applying to NVI in D as well, that I'll post later.


-- 
Apr 27 2008
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #1 from wbaxter gmail.com  2008-04-28 02:07 -------
That would open the door to the dreaded diamond pattern.

You'd just have the compiler generate ambiguity errors in those cases I
suppose?


-- 
Apr 28 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #2 from andrei metalanguage.com  2008-04-28 02:21 -------
(In reply to comment #1)
 That would open the door to the dreaded diamond pattern.
 
 You'd just have the compiler generate ambiguity errors in those cases I
 suppose?

The diamond pattern can't occur in schemes with single inheritance of implementation. --
Apr 28 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=2050
 
 
 
 
 
 ------- Comment #2 from andrei metalanguage.com  2008-04-28 02:21 -------
 (In reply to comment #1)
 That would open the door to the dreaded diamond pattern.

 You'd just have the compiler generate ambiguity errors in those cases I
 suppose?

The diamond pattern can't occur in schemes with single inheritance of implementation.

That's true, but the purpose of interfaces is to allow for multiple inheritance in a safe way. Say you have two interfaces, IZombie from Library A and IPirate from Library B. You have a class ZombiePirate that implements both these interfaces. Right now, IZombie has a final method "dance()", and IPirate has the dance() method as virtual. All is well, since a call to an instance's dance() method would result in IZombie.dance()'s implementation being called. But if IPirate suddenly got a dance() implementation, your code would break simply by updating Library B.
Apr 28 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050


aarti interia.pl changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |aarti interia.pl




------- Comment #3 from aarti interia.pl  2008-04-28 03:56 -------
It seems that same rationale applies to static functions in interfaces.
Currently below code doesn't work, as static functions can not have body in
interface.

---
int a;
interface A {
  static int number() {
    return a;
  }
}
---

Current situation is just plainly wrong as it is possible to put static
functions into interfaces and it is not possible to use them at all - linker
error is emitted during compilation (what is understandable as static functions
are not virtual).


-- 
Apr 28 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=2050
 
 
 aarti interia.pl changed:
 
            What    |Removed                     |Added
 ----------------------------------------------------------------------------
                  CC|                            |aarti interia.pl
 
 
 
 
 ------- Comment #3 from aarti interia.pl  2008-04-28 03:56 -------
 It seems that same rationale applies to static functions in interfaces.
 Currently below code doesn't work, as static functions can not have body in
 interface.
 
 ---
 int a;
 interface A {
   static int number() {
     return a;
   }
 }
 ---
 
 Current situation is just plainly wrong as it is possible to put static
 functions into interfaces and it is not possible to use them at all - linker
 error is emitted during compilation (what is understandable as static functions
 are not virtual).

You should be able to call them on the interface: If you have: class B : A {} void main() { A a = new B(); B b = new B(); A.number(); // Should work fine, so here's the bug a.number(); // Maybe should work....? b.number(); // Should NOT work }
Apr 28 2008
prev sibling next sibling parent reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #6 from andrei metalanguage.com  2008-04-28 11:12 -------
(In reply to comment #5)
 d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=2050
 
 
 
 
 
 ------- Comment #2 from andrei metalanguage.com  2008-04-28 02:21 -------
 (In reply to comment #1)
 That would open the door to the dreaded diamond pattern.

 You'd just have the compiler generate ambiguity errors in those cases I
 suppose?

The diamond pattern can't occur in schemes with single inheritance of implementation.

That's true, but the purpose of interfaces is to allow for multiple inheritance in a safe way. Say you have two interfaces, IZombie from Library A and IPirate from Library B. You have a class ZombiePirate that implements both these interfaces. Right now, IZombie has a final method "dance()", and IPirate has the dance() method as virtual. All is well, since a call to an instance's dance() method would result in IZombie.dance()'s implementation being called. But if IPirate suddenly got a dance() implementation, your code would break simply by updating Library B.

Such cases would be flagged as ambiguous. --
Apr 28 2008
parent Robert Fraser <fraserofthenight gmail.com> writes:
d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=2050
 
 
 
 
 
 ------- Comment #6 from andrei metalanguage.com  2008-04-28 11:12 -------
 (In reply to comment #5)
 d-bugmail puremagic.com wrote:
 http://d.puremagic.com/issues/show_bug.cgi?id=2050





 ------- Comment #2 from andrei metalanguage.com  2008-04-28 02:21 -------
 (In reply to comment #1)
 That would open the door to the dreaded diamond pattern.

 You'd just have the compiler generate ambiguity errors in those cases I
 suppose?

implementation.

inheritance in a safe way. Say you have two interfaces, IZombie from Library A and IPirate from Library B. You have a class ZombiePirate that implements both these interfaces. Right now, IZombie has a final method "dance()", and IPirate has the dance() method as virtual. All is well, since a call to an instance's dance() method would result in IZombie.dance()'s implementation being called. But if IPirate suddenly got a dance() implementation, your code would break simply by updating Library B.

Such cases would be flagged as ambiguous.

Right, but the ambiguity would be caused at no fault of the code being compiled, but because something changed in a different module. In many ways, it's similar to hijacking.
Apr 28 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #7 from andrei metalanguage.com  2008-04-28 11:14 -------
(In reply to comment #3)
 It seems that same rationale applies to static functions in interfaces.

I agree. --
Apr 28 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050


bugzilla digitalmars.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|normal                      |enhancement




-- 
May 14 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #9 from sandford jhu.edu  2009-04-04 09:53 -------
(In reply to comment #0)
This seems to break composability:

interface I1 { final int foo() {return 1;} }
interface I2 { final int foo() {return 2;} }

class A: I1, I2 {}

Whose foo does A choose? And how is it resolved? (given you can't drop one of
the interfaces). And consider

class B: I1, I2 { final int foo() {return 3;} }
B b = new B();
I1 i1 = b;
I2 i2 = b;
assert( i1.foo == 1 );
assert( i2.foo == 2 );
assert(  b.foo == 3 );


-- 
Apr 04 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #10 from sandford jhu.edu  2009-04-04 10:01 -------
(In reply to comment #0)
 Consider:
 
 interface Foo
 {
     void bar();
     final void baz() { bar; bar; }
 }

How is this superior to the current interface + mixin approach? Or an mixin-able interface approach?: class A:Foo { mixin Foo; // Add Foo's final/static method bodies to A } --
Apr 04 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050





------- Comment #11 from andrei metalanguage.com  2009-04-04 10:58 -------
(In reply to comment #9)
 (In reply to comment #0)
 This seems to break composability:
 
 interface I1 { final int foo() {return 1;} }
 interface I2 { final int foo() {return 2;} }
 
 class A: I1, I2 {}
 
 Whose foo does A choose? And how is it resolved? (given you can't drop one of
 the interfaces).

I think that's an ambiguity. It might be busted by having A write e.g. alias I1.foo foo;
 And consider
 
 class B: I1, I2 { final int foo() {return 3;} }
 B b = new B();
 I1 i1 = b;
 I2 i2 = b;
 assert( i1.foo == 1 );
 assert( i2.foo == 2 );
 assert(  b.foo == 3 );

A good use of final functions is to enable the non-virtual interface idiom. The point of that idiom is partially that you cannot override final functions in interfaces. --
Apr 04 2009
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050


Rob Jacques <sandford jhu.edu> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |sandford jhu.edu


--- Comment #12 from Rob Jacques <sandford jhu.edu> 2010-07-07 07:23:10 PDT ---
Wasn't this added in D 2.040. (i.e. should this be closed?)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jul 07 2010
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=2050


yebblies <yebblies gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |yebblies gmail.com
         Resolution|                            |FIXED


--- Comment #13 from yebblies <yebblies gmail.com> 2011-06-10 08:49:07 PDT ---
Added in dmd2.040

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jun 10 2011