Thread overview | |||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote: > Some interesting blog post: http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/ > > It's a post about a common problem in class design, I've ran into it a few times in D too. [...] Interesting concept. So "polite" overriding is simply a kind of override where the derived class method has a vtable entry separate from the base class method's entry (and thus needs explicit invocation from the base class), whereas the usual "impolite" overriding is a kind of override where the derived class method replaces the vtable entry of the base class method. I can see use cases for both kinds of overriding. Interestingly enough, in the "polite" overriding case, the call to inner is undefined until it's defined in the derived class. Which means that a method that calls inner is a kind of pseudo-abstract method (since abstract methods are those that *must* be implemented by the derived class). So if we were to implement this in D, we could extend the meaning of 'abstract': class Base { // The current, usual overridable method void replaceMe() { writeln("A"); } // Abstract, because chain(chainMe) is undefined until // the derived class implements it. abstract void chainMe() { writeln("B"); inner.chainMe(); // call derived class method // 'inner' is a tentative // keyword writeln("C"); } } class Derived : Base { override replaceMe() { writeln("D"); Base.replaceMe(); writeln("E"); } // Base.chainMe is abstract, so we have to implement // this method. override void chainMe() { writeln("F"); } } void main() { auto d = new Derived(); d.replaceMe(); // prints D A E d.chainMe(); // prints B F C } T -- Food and laptops don't mix. |
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2012-12-20 01:06, H. S. Teoh wrote: > On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote: >> Some interesting blog post: >> http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/ >> >> It's a post about a common problem in class design, I've ran into it a >> few times in D too. > [...] > > Interesting concept. So "polite" overriding is simply a kind of override > where the derived class method has a vtable entry separate from the base > class method's entry (and thus needs explicit invocation from the base > class), whereas the usual "impolite" overriding is a kind of override > where the derived class method replaces the vtable entry of the base > class method. > > I can see use cases for both kinds of overriding. > > Interestingly enough, in the "polite" overriding case, the call to inner > is undefined until it's defined in the derived class. Which means that a > method that calls inner is a kind of pseudo-abstract method (since > abstract methods are those that *must* be implemented by the derived > class). So if we were to implement this in D, we could extend the > meaning of 'abstract': > > class Base { > // The current, usual overridable method > void replaceMe() { > writeln("A"); > } > > // Abstract, because chain(chainMe) is undefined until > // the derived class implements it. > abstract void chainMe() { > writeln("B"); > inner.chainMe(); // call derived class method > // 'inner' is a tentative > // keyword > writeln("C"); > } > } > > class Derived : Base { > override replaceMe() { > writeln("D"); > Base.replaceMe(); > writeln("E"); > } > > // Base.chainMe is abstract, so we have to implement > // this method. > override void chainMe() { > writeln("F"); > } > } > > void main() { > auto d = new Derived(); > d.replaceMe(); // prints D A E > d.chainMe(); // prints B F C > } > > > T > What's the difference compared to calling "super". -- /Jacob Carlborg |
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jacob Carlborg | On Thu, Dec 20, 2012 at 08:26:18AM +0100, Jacob Carlborg wrote: > On 2012-12-20 01:06, H. S. Teoh wrote: > >On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote: > >>Some interesting blog post: http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/ [...] > >Interestingly enough, in the "polite" overriding case, the call to inner is undefined until it's defined in the derived class. Which means that a method that calls inner is a kind of pseudo-abstract method (since abstract methods are those that *must* be implemented by the derived class). So if we were to implement this in D, we could extend the meaning of 'abstract': > > > > class Base { > > // The current, usual overridable method > > void replaceMe() { > > writeln("A"); > > } > > > > // Abstract, because chain(chainMe) is undefined until > > // the derived class implements it. > > abstract void chainMe() { > > writeln("B"); > > inner.chainMe(); // call derived class method > > // 'inner' is a tentative > > // keyword > > writeln("C"); > > } > > } > > > > class Derived : Base { > > override replaceMe() { > > writeln("D"); > > Base.replaceMe(); > > writeln("E"); > > } > > > > // Base.chainMe is abstract, so we have to implement > > // this method. > > override void chainMe() { > > writeln("F"); > > } > > } > > > > void main() { > > auto d = new Derived(); > > d.replaceMe(); // prints D A E > > d.chainMe(); // prints B F C > > } > > > > > >T > > > > What's the difference compared to calling "super". [...] The difference is that you can do things like this: class Base { abstract void chainMe() { if (condition) { chainMe(); // recursion } else { inner.chainMe(); } } } Which cannot be easily reproduced using .super. T -- Ruby is essentially Perl minus Wall. |
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote:
> On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote:
>> Some interesting blog post:
>> http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/
>>
>> It's a post about a common problem in class design, I've ran into it a
>> few times in D too.
> [...]
>
> Interesting concept. So "polite" overriding is simply a kind of override
> where the derived class method has a vtable entry separate from the base
> class method's entry (and thus needs explicit invocation from the base
> class), whereas the usual "impolite" overriding is a kind of override
> where the derived class method replaces the vtable entry of the base
> class method.
>
> I can see use cases for both kinds of overriding.
>
> Interestingly enough, in the "polite" overriding case, the call to inner
> is undefined until it's defined in the derived class. Which means that a
> method that calls inner is a kind of pseudo-abstract method (since
> abstract methods are those that *must* be implemented by the derived
> class). So if we were to implement this in D, we could extend the
> meaning of 'abstract':
>
> class Base {
> // The current, usual overridable method
> void replaceMe() {
> writeln("A");
> }
>
> // Abstract, because chain(chainMe) is undefined until
> // the derived class implements it.
> abstract void chainMe() {
> writeln("B");
> inner.chainMe(); // call derived class method
> // 'inner' is a tentative
> // keyword
> writeln("C");
> }
> }
>
> class Derived : Base {
> override replaceMe() {
> writeln("D");
> Base.replaceMe();
> writeln("E");
> }
>
> // Base.chainMe is abstract, so we have to implement
> // this method.
> override void chainMe() {
> writeln("F");
> }
> }
>
> void main() {
> auto d = new Derived();
> d.replaceMe(); // prints D A E
> d.chainMe(); // prints B F C
> }
>
>
> T
This is trivially implemented with a simple OO design pattern in any usual OO language:
class Base {
public override precious() {...}
private void myPrecious() {
before();
precious();
after();
}
}
class Derived {
override precious() {...}
}
Having syntax sugar is redundant given how simple this pattern is.
|
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to foobar | On Thursday, 20 December 2012 at 07:48:12 UTC, foobar wrote:
> On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote:
>> On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote:
>>> Some interesting blog post:
>>> http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/
>>>
>>> It's a post about a common problem in class design, I've ran into it a
>>> few times in D too.
>> [...]
>>
>> Interesting concept. So "polite" overriding is simply a kind of override
>> where the derived class method has a vtable entry separate from the base
>> class method's entry (and thus needs explicit invocation from the base
>> class), whereas the usual "impolite" overriding is a kind of override
>> where the derived class method replaces the vtable entry of the base
>> class method.
>>
>> I can see use cases for both kinds of overriding.
>>
>> Interestingly enough, in the "polite" overriding case, the call to inner
>> is undefined until it's defined in the derived class. Which means that a
>> method that calls inner is a kind of pseudo-abstract method (since
>> abstract methods are those that *must* be implemented by the derived
>> class). So if we were to implement this in D, we could extend the
>> meaning of 'abstract':
>>
>> class Base {
>> // The current, usual overridable method
>> void replaceMe() {
>> writeln("A");
>> }
>>
>> // Abstract, because chain(chainMe) is undefined until
>> // the derived class implements it.
>> abstract void chainMe() {
>> writeln("B");
>> inner.chainMe(); // call derived class method
>> // 'inner' is a tentative
>> // keyword
>> writeln("C");
>> }
>> }
>>
>> class Derived : Base {
>> override replaceMe() {
>> writeln("D");
>> Base.replaceMe();
>> writeln("E");
>> }
>>
>> // Base.chainMe is abstract, so we have to implement
>> // this method.
>> override void chainMe() {
>> writeln("F");
>> }
>> }
>>
>> void main() {
>> auto d = new Derived();
>> d.replaceMe(); // prints D A E
>> d.chainMe(); // prints B F C
>> }
>>
>>
>> T
>
> This is trivially implemented with a simple OO design pattern in any usual OO language:
>
> class Base {
> public override precious() {...}
> private void myPrecious() {
> before();
> precious();
> after();
> }
> }
>
> class Derived {
> override precious() {...}
> }
>
> Having syntax sugar is redundant given how simple this pattern is.
No because in your example you have to write Base already for that specific use case, whereas in BETA is up to the derived class to do as it please.
|
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh |
class Base
{
void chainMe()
{
...doStuff()
inner(); //calls a derived chainMe
}
}
class Derived1:Base
class Derived2:Base
Derived2 der2 = new Derived2();
Derived1 der1 = cast(Derived1) der;
der.chainMe(); // calls chainMe from Base.
I assume it would have to call the chainMe from the Base first and not
from any of the Derived.
On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote:
> On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote:
>> Some interesting blog post:
>> http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/
>>
>> It's a post about a common problem in class design, I've ran into it a
>> few times in D too.
> [...]
>
> Interesting concept. So "polite" overriding is simply a kind of override
> where the derived class method has a vtable entry separate from the base
> class method's entry (and thus needs explicit invocation from the base
> class), whereas the usual "impolite" overriding is a kind of override
> where the derived class method replaces the vtable entry of the base
> class method.
>
> I can see use cases for both kinds of overriding.
>
> Interestingly enough, in the "polite" overriding case, the call to inner
> is undefined until it's defined in the derived class. Which means that a
> method that calls inner is a kind of pseudo-abstract method (since
> abstract methods are those that *must* be implemented by the derived
> class). So if we were to implement this in D, we could extend the
> meaning of 'abstract':
>
> class Base {
> // The current, usual overridable method
> void replaceMe() {
> writeln("A");
> }
>
> // Abstract, because chain(chainMe) is undefined until
> // the derived class implements it.
> abstract void chainMe() {
> writeln("B");
> inner.chainMe(); // call derived class method
> // 'inner' is a tentative
> // keyword
> writeln("C");
> }
> }
>
> class Derived : Base {
> override replaceMe() {
> writeln("D");
> Base.replaceMe();
> writeln("E");
> }
>
> // Base.chainMe is abstract, so we have to implement
> // this method.
> override void chainMe() {
> writeln("F");
> }
> }
>
> void main() {
> auto d = new Derived();
> d.replaceMe(); // prints D A E
> d.chainMe(); // prints B F C
> }
>
>
> T
|
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paulo Pinto | On Thursday, 20 December 2012 at 08:12:54 UTC, Paulo Pinto wrote:
> On Thursday, 20 December 2012 at 07:48:12 UTC, foobar wrote:
>> On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote:
>>> On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote:
>>>> Some interesting blog post:
>>>> http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/
>>>>
>>>> It's a post about a common problem in class design, I've ran into it a
>>>> few times in D too.
>>> [...]
>>>
>>> Interesting concept. So "polite" overriding is simply a kind of override
>>> where the derived class method has a vtable entry separate from the base
>>> class method's entry (and thus needs explicit invocation from the base
>>> class), whereas the usual "impolite" overriding is a kind of override
>>> where the derived class method replaces the vtable entry of the base
>>> class method.
>>>
>>> I can see use cases for both kinds of overriding.
>>>
>>> Interestingly enough, in the "polite" overriding case, the call to inner
>>> is undefined until it's defined in the derived class. Which means that a
>>> method that calls inner is a kind of pseudo-abstract method (since
>>> abstract methods are those that *must* be implemented by the derived
>>> class). So if we were to implement this in D, we could extend the
>>> meaning of 'abstract':
>>>
>>> class Base {
>>> // The current, usual overridable method
>>> void replaceMe() {
>>> writeln("A");
>>> }
>>>
>>> // Abstract, because chain(chainMe) is undefined until
>>> // the derived class implements it.
>>> abstract void chainMe() {
>>> writeln("B");
>>> inner.chainMe(); // call derived class method
>>> // 'inner' is a tentative
>>> // keyword
>>> writeln("C");
>>> }
>>> }
>>>
>>> class Derived : Base {
>>> override replaceMe() {
>>> writeln("D");
>>> Base.replaceMe();
>>> writeln("E");
>>> }
>>>
>>> // Base.chainMe is abstract, so we have to implement
>>> // this method.
>>> override void chainMe() {
>>> writeln("F");
>>> }
>>> }
>>>
>>> void main() {
>>> auto d = new Derived();
>>> d.replaceMe(); // prints D A E
>>> d.chainMe(); // prints B F C
>>> }
>>>
>>>
>>> T
>>
>> This is trivially implemented with a simple OO design pattern in any usual OO language:
>>
>> class Base {
>> public override precious() {...}
>> private void myPrecious() {
>> before();
>> precious();
>> after();
>> }
>> }
>>
>> class Derived {
>> override precious() {...}
>> }
>>
>> Having syntax sugar is redundant given how simple this pattern is.
>
> No because in your example you have to write Base already for that specific use case, whereas in BETA is up to the derived class to do as it please.
Have you read the article?
The Beta design (btw, it's the same in smalltalk - the article is wrong on that point) is to give control to the base class. The base class in beta is written specifically for that use case and the derived has no-control. That's the entire point of this design. It is basically a restriction to allow only overriding abstract methods (with a slightly more convenient syntax)
|
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh |
Contract Programming :-)
int chain(...)
{
preConstracts()
inner.chain() // calls derived chain function
postConstracts()
return ...
}
Scly
On Thursday, 20 December 2012 at 00:07:49 UTC, H. S. Teoh wrote:
> On Thu, Dec 20, 2012 at 12:11:34AM +0100, Andrej Mitrovic wrote:
>> Some interesting blog post:
>> http://journal.stuffwithstuff.com/2012/12/19/the-impoliteness-of-overriding-methods/
>>
>> It's a post about a common problem in class design, I've ran into it a
>> few times in D too.
> [...]
>
> Interesting concept. So "polite" overriding is simply a kind of override
> where the derived class method has a vtable entry separate from the base
> class method's entry (and thus needs explicit invocation from the base
> class), whereas the usual "impolite" overriding is a kind of override
> where the derived class method replaces the vtable entry of the base
> class method.
>
> I can see use cases for both kinds of overriding.
>
> Interestingly enough, in the "polite" overriding case, the call to inner
> is undefined until it's defined in the derived class. Which means that a
> method that calls inner is a kind of pseudo-abstract method (since
> abstract methods are those that *must* be implemented by the derived
> class). So if we were to implement this in D, we could extend the
> meaning of 'abstract':
>
> class Base {
> // The current, usual overridable method
> void replaceMe() {
> writeln("A");
> }
>
> // Abstract, because chain(chainMe) is undefined until
> // the derived class implements it.
> abstract void chainMe() {
> writeln("B");
> inner.chainMe(); // call derived class method
> // 'inner' is a tentative
> // keyword
> writeln("C");
> }
> }
>
> class Derived : Base {
> override replaceMe() {
> writeln("D");
> Base.replaceMe();
> writeln("E");
> }
>
> // Base.chainMe is abstract, so we have to implement
> // this method.
> override void chainMe() {
> writeln("F");
> }
> }
>
> void main() {
> auto d = new Derived();
> d.replaceMe(); // prints D A E
> d.chainMe(); // prints B F C
> }
>
>
> T
|
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On 2012-12-20 08:41, H. S. Teoh wrote: > The difference is that you can do things like this: > > class Base { > abstract void chainMe() { > if (condition) { > chainMe(); // recursion > } else { > inner.chainMe(); > } > } > } > > Which cannot be easily reproduced using .super. Oh, it's the super class that's calling the subclass? -- /Jacob Carlborg |
December 20, 2012 Re: The impoliteness of overriding methods | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | This polite overriding is a nice idiom. But it does not solve the most frequent problem I have at work (in C++)
Assume you have a customer facing class they derive from to implement own features.
abstract class Base
{
abstract void doStuff();
}
The customer now derives from this class and implements doStuff. Because it is abstract he does not call the base implementation.
Now you have to do some changes and suddenly the doStuff method is no longer abstract and does something important that should always be executed.
abstract class Base
{
void doStuff(){ prepareSomething(); }
}
The best you can do is put a line into the changelog "make sure to call the base implementation of Base.doStuff...". Which the customer most likely won't read and thus usually will fill a issue report with the Support deparment, because the code breaks.
If there would be some kind of attribute supported by the compiler, such as that the compiler ensures that the base implementation is always called if the function is annotated with this attribute the customer would automatically be reminded by the compiler, and this would not be an issue.
It could look something like this:
abstract class Base
{
@mustcall void doStuff(){ prepareSomething(); }
}
Making a helper method that is called instead of doStuff is usually not an option, because the customer might have calls to doStuff in his code, which would still lead to a wrong execution path.
--
Kind Regards
Benjamin Thaut
|
Copyright © 1999-2021 by the D Language Foundation