implement vs override
Quirin Schroll
qs.il.paperinik at gmail.com
Mon Nov 3 12:29:44 UTC 2025
On Sunday, 2 November 2025 at 00:49:36 UTC, Peter C wrote:
> On Friday, 31 October 2025 at 23:36:57 UTC, Quirin Schroll
> wrote:
>>
>> ...
>> This is a good idea for nomenclature in documentation, but it
>> doesn't work with the language. You can implement an interface
>> method by inheriting from a class that defines the method
>> without the base class implementing the interface.
>
> If D had a C# like 'explicit' interface declaration:
> ```d
> module myModule;
> @safe:
> private:
>
> void main()
> {
>
> }
>
> interface Isomething
> {
> void someMethod();
> }
>
> class Base
> {
>
> void someMethod()
> {
>
> }
> }
>
> class Derived : Base, Isomething
> {
> // Here, I am intentionally binding the interface requirement
> // to a concrete method, rather than letting the inherited
> method automatically
> // fulfill the interface contract.
>
> void ISomething.SomeMethod()
> {
> // This method satisfies the interface, but it's only
> accessible
> // when the object is cast to the ISomething type.
> }
> }
> ```
Yes, I ran into this issue in practice in C++. C++/CLI actually
supports this quite elegantly (elegantly for C++) using `=`:
```cpp
class Derived : public Base, public Interface
{
…
void myCustomName() const = Interface::interfaceMethod;
};
void Derived::myCustomName() const { … }
```
This is an actual limitation in D (and IIRC, also in Java): If
two interfaces have methods with the same name and parameter
list, you ***cannot*** implement them differently. This defeats
the whole purpose of interfaces which are supposed not to be duck
typing (it’s a duck if and only if it happens to have `void
quack()`), but explicit (it’s a duck if and only if it implements
`std.quacking.IDuck`).
I think I suggested something like that for D, hooking the
`override` keyword:
```d
// My proposal from memory
interface I1 { void iface(int); }
interface I2 { void iface(int); }
class C : I1, I2
{
override(I1)
void iface1(int) { }
override(I2)
void iface2(int) { }
}
void main()
{
C c = new C;
c.iface(); // Error, `C` does not have `iface`; did you mean
`iface1` or `iface2`?
c.I1.iface(); // Okay
c.I2.iface(); // Okay
}
```
The original proposal went further and would also allow overrides
contravariant in parameter lists:
```d
class Base { }
class Derived : Base { }
interface I { Base f(Derived); }
class C : I
{
override(I.f(Derived))
Derived f(Base) const => new Derived;
}
```
From a theoretical and implementation (vtable) standpoint,
there’s nothing wrong with doing this. It’s completely in-line
with the Liskov substitution principle.
On the topic of the original post, the difference between a base
class and an interface is very minor. D, Java, C#, and many other
single-inheritance languages make you have a trade-off between an
inheritable construct having non-static data members (class) and
allowing it to be freely inherited from alongside something else
(interface).
More information about the Digitalmars-d
mailing list