www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - implement vs override

reply Peter C <peterc gmail.com> writes:
NOTE: It's just an idea, not a proposal.

I'm a big fan of clarity in design.

Clarity is what makes your design understandable and maintainable.

'implement' - implements an abstract/interface method - 
First-time definition

'override' - overrrides a concrete base method - Replaces or 
extends existing logic


interface Clickable
{
   void onClick();
}

class Component
{
   void render()
   {
       writeln("Rendering generic component");
   }
}

class Button : Component, Clickable
{
   implement void onClick()
   {
       // First-time implementation of Clickable.onClick
       writeln("Button clicked!");
   }

   override void render()
   {
       // Overrides Component.render
       writeln("Rendering a button");
   }
}

---- currently you can do it this way in D, and it provide very 
little clarity at all.

interface Clickable
{
   void onClick();
}

class Component
{
   void render()
   {
       writeln("Rendering generic component");
   }
}

class Button : Component, Clickable
{
   void onClick()
   {
       writeln("Button clicked!");
   }

   override void render()
   {
       writeln("Rendering a button");
   }
}
Oct 31
next sibling parent Peter C <peterc gmail.com> writes:
On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:


to have in D:

interface Clickable
{
   void onClick();
}

class Component
{
   void render()
   {
       writeln("Rendering generic component");
   }
}

class Button : Component, Clickable
{
   void Clickable:onClick()
   {
       // First-time implementation of Clickable.onClick
       writeln("Button clicked!");
   }

   override void render()
   {
       // Overrides Component.render
       writeln("Rendering a button");
   }
}


--- And when it becomes even more confusing:

interface Isomething
{
   void someMethod();
}

class Base
{
   void someMethod() { }
}

class Derived : Base, Isomething
{
   override void someMethod() { } // ??

// Error: Method 'someMethod' matches both a base class and 
interface signature. Use override or explicit interface 
implementation to clarify."

}
Oct 31
prev sibling next sibling parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:
 NOTE: It's just an idea, not a proposal.

 I'm a big fan of clarity in design.

 Clarity is what makes your design understandable and 
 maintainable.

 'implement' - implements an abstract/interface method - 
 First-time definition

 'override' - overrrides a concrete base method - Replaces or 
 extends existing logic
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.
Oct 31
next sibling parent reply Peter C <peterc gmail.com> writes:
On Friday, 31 October 2025 at 23:36:57 UTC, Quirin Schroll wrote:
 On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:
 NOTE: It's just an idea, not a proposal.

 I'm a big fan of clarity in design.

 Clarity is what makes your design understandable and 
 maintainable.

 'implement' - implements an abstract/interface method - 
 First-time definition

 'override' - overrrides a concrete base method - Replaces or 
 extends existing logic
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.
ok. interesting... interface IGreeter { void greet(); } class Base { void greet() {} // Really, there should be a complier error here. // e.g "Error: Method 'greet' matches both a base class and interface signature." // so ok...what to do here?? remove or rename? // I don't think Base should sucessfully compile under this circumstance. } class Derived : Base, IGreeter { }
Oct 31
parent Peter C <peterc gmail.com> writes:
On Friday, 31 October 2025 at 23:49:06 UTC, Peter C wrote:
 On Friday, 31 October 2025 at 23:36:57 UTC, Quirin Schroll 
 wrote:
 On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:
 NOTE: It's just an idea, not a proposal.

 I'm a big fan of clarity in design.

 Clarity is what makes your design understandable and 
 maintainable.

 'implement' - implements an abstract/interface method - 
 First-time definition

 'override' - overrrides a concrete base method - Replaces or 
 extends existing logic
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.
ok. interesting... interface IGreeter { void greet(); } class Base { void greet() {} // Really, there should be a complier error here. // e.g "Error: Method 'greet' matches both a base class and interface signature." // so ok...what to do here?? remove or rename? // I don't think Base should sucessfully compile under this circumstance. } class Derived : Base, IGreeter { }
oops. interface IGreeter { void greet(); } class Base { void greet() {} } class Derived : Base, IGreeter { // "Error: class Derived inherits a base class method that matches IGreeter.greet(). Use an explicit interface declaration to implement Greeter.greet()" }
Oct 31
prev sibling next sibling parent reply Peter C <peterc gmail.com> writes:
On Friday, 31 October 2025 at 23:36:57 UTC, Quirin Schroll wrote:
 ..
 You can implement an interface method by inheriting from a 
 class that defines the method without the base class 
 implementing the interface.
ok. that took me a while to get my head around ;-) -------------------------------- interface IsomeInterface { void someMethod(); } class Base { void someMethod() { } // virtual by default in D. } class Derived : Base, IsomeInterface { // Note: no mention of void someMethod() anywhere. } ------------------------------- ok. now we have the 'accidental implementation' problem. The compiler really should produce an error message here, in relation to Derived:
 Error: 'Base.someMethod' signature conflicts with 
 'IsomeInterface.someMethod' signature. Add an explicitly 
 declared void someMethod() in Derived, to resolve this 
 ambiquity.
Fortunately in D, 'override' is now required to override a base class method. So now, the programmer *must* do either of these things: (1) class Derived : Base, IsomeInterface { // NOTE: D doesn't have an 'implement' keyword for implementing an interface method. void someMethod() {} // implementing the interface contract here } (2) class Derived : Base, IsomeInterface { override void someMethod() {} // overiding the virtual member inherited from Base. } Either way, the compiler is now satisfied that you have resolved the 'accidental implementation' problem. I don't expect D to make a change here, but this is how I would have expected a compiler to behave in any case. I think the Carbon language may have resolved this.
Oct 31
parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Saturday, 1 November 2025 at 06:41:57 UTC, Peter C wrote:
 ok. now we have the 'accidental implementation' problem.
There is nothing "accidental" there - you have made the decision to inherit from Base, and should know what that means!
Nov 01
parent reply Peter C <peterc gmail.com> writes:
On Saturday, 1 November 2025 at 13:47:22 UTC, Dejan Lekic wrote:
 On Saturday, 1 November 2025 at 06:41:57 UTC, Peter C wrote:
 ok. now we have the 'accidental implementation' problem.
There is nothing "accidental" there - you have made the decision to inherit from Base, and should know what that means!
Just because you know what it means, doesn't mean I know what it means. The compiler sure seems to know what it means. But it's not an absolute that in this situation that the programmer would know what it means - and I specifically use myself as a case study here ;-) Also, will the next programmer maintaining your code know what it means? interface Isomething { void someMethod(); } class Base { void someMethod() {} } class Derived : Base, Isomething { // is Derived fullfilling the semantic requirements of interface contract here? }
Nov 01
parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Sunday, 2 November 2025 at 00:00:35 UTC, Peter C wrote:
 Just because you know what it means, doesn't mean I know what 
 it means.
I am trying very hard to understand you here - you, as developer who wrote the code, deliberately made a decision to inherit from Base class. This means you _do know_ what it means (what that class does).
Nov 02
parent reply Peter C <peterc gmail.com> writes:
On Sunday, 2 November 2025 at 11:33:56 UTC, Dejan Lekic wrote:
 On Sunday, 2 November 2025 at 00:00:35 UTC, Peter C wrote:
 Just because you know what it means, doesn't mean I know what 
 it means.
I am trying very hard to understand you here - you, as developer who wrote the code, deliberately made a decision to inherit from Base class. This means you _do know_ what it means (what that class does).
There is no indication to me that Base intended to implement the semantic requirements of the interface. Do you understand that? And yet, Base.someMethod() is considered an implementation of the interface. I understand that the compiler undertands this (because it has the same signature), but really, the compiler is just taking the easiest possible path here. It's still not clear to *me* (regardless of the rules here) that by simply inherting a method from Base that has the same signature, that it automatically satisfies the semantic requirements of the interface. The person maintaining this code will likely ask the same question I did - does Derived implement the semantic requirement of the interface, or not? this question straight away. The intent would have been clear, and I would have understood immediately that Derived has indeed implemented the semantic requirement of the interface. D's starting to remind me of that scene in Ghostbusters, where Peter drives up with (what will become) the ghostbusters vehicle. i.e. look promising, but will need a lot of work.
Nov 02
parent reply Serg Gini <kornburn yandex.ru> writes:
On Sunday, 2 November 2025 at 23:13:08 UTC, Peter C wrote:
 On Sunday, 2 November 2025 at 11:33:56 UTC, Dejan Lekic wrote:
why do you think Base is considered as an implementation of the interface?
Nov 02
parent reply Peter C <peterc gmail.com> writes:
On Monday, 3 November 2025 at 07:26:24 UTC, Serg Gini wrote:
 On Sunday, 2 November 2025 at 23:13:08 UTC, Peter C wrote:
 On Sunday, 2 November 2025 at 11:33:56 UTC, Dejan Lekic wrote:
why do you think Base is considered as an implementation of the interface?
Actually I've confused myself (and likely others) because I thought this code below actually compiled at one stage (with no error) - turns out... it won't compile. It will produce an error: Error: class `myModule.Derived` interface function `void someMethod()` is not implemented interface method in a derived class if the signatures match. In D, it seems the rule is a little different: A class that claims to implement an interface must itself provide implementations for all interface methods. Inherited methods from a base class are not counted *unless* the compiler can directly see that the derived class provides them (i.e. via an 'override' of the base method). Turns out I prefer the way D *prevents* this from compiling, and actually requires that you 'override' the method in Derived. That signals an explicit action by the programmer to deal with this The only way to get the code below to compile in D, is to 'override' someMethod in Derived. But... .. what if I need to keep the semantics of the base class method (or override for some reason), but also implement the semantics of the interface contract? - which D does not have. I won't spend more time on this, cause it's pretty rare scenario in the work I do, but I've learnt something useful, so wasn't a complete waste of time - for me anyway ;-) btw. Would be interesting to know if anyone in the past has ever what the response was. ................................. module myModule; import std; void main() { Derived d = new Derived(); d.someMethod(); } interface Isomething { void someMethod(); } class Base { void someMethod() { writeln("Hello from Base"); } } class Derived : Base, Isomething { } .................................
Nov 03
next sibling parent reply Serg Gini <kornburn yandex.ru> writes:
On Monday, 3 November 2025 at 08:02:06 UTC, Peter C wrote:
 But...

 .. what if I need to keep the semantics of the base class 
 method (or override for some reason), but also implement the 
 semantics of the interface contract?
This is all theoretical - without code example doesn't mean anything. Drop all prompt that was used before and provide the model name that used for this text generation.
Nov 03
parent reply Peter C <peterc gmail.com> writes:
On Monday, 3 November 2025 at 08:34:02 UTC, Serg Gini wrote:
 On Monday, 3 November 2025 at 08:02:06 UTC, Peter C wrote:
 But...

 .. what if I need to keep the semantics of the base class 
 method (or override for some reason), but also implement the 
 semantics of the interface contract?
This is all theoretical - without code example doesn't mean anything. Drop all prompt that was used before and provide the model name that used for this text generation.
'the model name' ?? Anyway...it's solved now. It turns out, that composition was the answer here. module myModule; safe: private: import std.stdio : writeln; interface Isomething { void someMethod(); } class Base { void someMethod() { writeln("Hello from Base"); } } class Derived : Isomething { Base base; // composition this() { base = new Base(); } // Interface implementation void someMethod() { writeln("Hello from Isomething in Derived"); } // Expose base behavior separately void callBase() { base.someMethod(); } } void main() { auto d = new Derived(); Isomething i = d; i.someMethod(); // "Hello from Isomething in Derived" d.callBase(); // "Hello from Base" }
Nov 03
parent reply Serg Gini <kornburn yandex.ru> writes:
On Monday, 3 November 2025 at 09:32:45 UTC, Peter C wrote:
 On Monday, 3 November 2025 at 08:34:02 UTC, Serg Gini wrote:
 On Monday, 3 November 2025 at 08:02:06 UTC, Peter C wrote:
'the model name' ?? Anyway...it's solved now. It turns out, that composition was the answer here.
So just to finalize for anyone who will read it. D doesn't have any issues
Nov 03
parent Peter C <peterc gmail.com> writes:
On Monday, 3 November 2025 at 10:26:59 UTC, Serg Gini wrote:
 On Monday, 3 November 2025 at 09:32:45 UTC, Peter C wrote:
 On Monday, 3 November 2025 at 08:34:02 UTC, Serg Gini wrote:
 On Monday, 3 November 2025 at 08:02:06 UTC, Peter C wrote:
'the model name' ?? Anyway...it's solved now. It turns out, that composition was the answer here.
So just to finalize for anyone who will read it. D doesn't have any issues
Well.. I wouldn't go that far ;-) other one is for my class, even though they share the same signature." the programmer has to reach for other patterns. So.. to your question -> programmers can decide for themselves whether they prefer the extra ceremony in D.
Nov 03
prev sibling parent Zealot <zealot planet.earth> writes:
On Monday, 3 November 2025 at 08:02:06 UTC, Peter C wrote:
 On Monday, 3 November 2025 at 07:26:24 UTC, Serg Gini wrote:
 [...]
Actually I've confused myself (and likely others) because I thought this code below actually compiled at one stage (with no error) - turns out... it won't compile. [...]
Base doesnt inherit from Isomething, so Base.someMethod doesn't implement the interface. so Derived sees Isomething and doesnt see any implementation for it. it doesnt simply take the same signature
Nov 03
prev sibling parent reply Peter C <peterc gmail.com> writes:
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.
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. } }
Nov 01
next sibling parent Worldeater <worldeater planet.earth> writes:
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:
 [...]
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. } }
the whole point of it is to not have to cast to interfaces, but just have the type behave a certain way. just use plain old composition if and alias the methods if you want this.
Nov 02
prev sibling parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
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.
```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 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).
Nov 03
parent Peter C <peterc gmail.com> writes:
On Monday, 3 November 2025 at 12:29:44 UTC, Quirin Schroll wrote:
 ..
Borrowing and idea from Carbon and Rust, you could group all the interface methods together in a dedicated block/scope using 'impl': It's nice and structured, and would scale very well for handling multiple interfaces. module myModule; safe: private: import std.stdio : writeln; interface IWorker { void start(); void stop(); int status(); } class Base { void start() { writeln("Base: starting generic process"); } void stop() { writeln("Base: stopping generic process"); } int status() { return 0; // 0 = idle } } class Derived : Base, IWorker { // Explicit interface implementation block impl(IWorker) { void start() { writeln("IWorker: initializing hardware"); } void stop() { writeln("IWorker: shutting down hardware"); } int status() { writeln("IWorker: reporting hardware status"); return 42; // pretend 42 = "active" } } } void main() { auto d = new Derived(); // Calls Base methods d.start(); // "Base: starting generic process" d.stop(); // "Base: stopping generic process" writeln(d.status()); // 0 // Calls IWorker methods IWorker w = d; w.start(); // "IWorker: initializing hardware" w.stop(); // "IWorker: shutting down hardware" writeln(w.status()); // 42 }
Nov 03
prev sibling parent reply Zealot <zealot planet.earth> writes:
On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:
 'implement' - implements an abstract/interface method - 
 First-time definition
use implement and build your own checker if you need this.
 I'm a big fan of clarity in design.
yeah, the java exception lists were that too. turns out people hate useless clutter and extra work.
Oct 31
next sibling parent Kapendev <alexandroskapretsos gmail.com> writes:
On Friday, 31 October 2025 at 23:39:29 UTC, Zealot wrote:
 On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:
 'implement' - implements an abstract/interface method - 
 First-time definition
use implement and build your own checker if you need this.
 I'm a big fan of clarity in design.
yeah, the java exception lists were that too. turns out people hate useless clutter and extra work.
Java's `throws` is kinda cute I think.
Oct 31
prev sibling parent Peter C <peterc gmail.com> writes:
On Friday, 31 October 2025 at 23:39:29 UTC, Zealot wrote:
 On Friday, 31 October 2025 at 22:58:04 UTC, Peter C wrote:
 'implement' - implements an abstract/interface method - 
 First-time definition
use implement and build your own checker if you need this.
 I'm a big fan of clarity in design.
yeah, the java exception lists were that too. turns out people hate useless clutter and extra work.
I kinda meant 'clarity to avoid ambiguity', not clarity to create clutter and extra work.
Oct 31