July 19, 2004
Berin Loritsch wrote:

>>>>> What's wrong with having all functions/methods being overridable
>>>>> unless there is a keywords saying don't do it?  This is something
>>>>> that works quite happily in the Java lanaguage.
>>>>>
>>>>> Having to explicitly say "I want this to be overriden" is quite
>>>>> annoying, as most of the time that is what I expect.
>>
>> I disagree with this completely.
> 
> Which part?  The part that says I have to explicitly state "I want to override" for each class/interface method from a parent class I might be working on?  Or the part that says overriding is expected unless told otherwise?

I think it's a good thing that a class designer be able to decide which methods can and can't be overridden.  D does provide this, which makes me a happy camper either way, but I prefer the explicit annotation.

Explicitly decorating a function as being overridable serves as a positive assertion that you want it to be so.  This carries with it a piece of your notion of how the class ought to be used: The class's own definition explicitly says "I was made to be subclassed in precisely this manner."

Negatives aren't as strong because they mean either yes or "no but I forgot to say so".

>> Implementation inheritance is a tricky problem because you not only have a public interface, you have a private invariant that must be maintained.  If any method can be overridden, your job gets a whole lot harder.
> 
> I really haven't run into this problem, and I have developed software
> for a few years now.  Mostly Java and C++.  I run into more problems because a language (or compiler in some cases) *doesn't* override a method I expect it to.

I agree that the C++ way is even worse. :)

I think, in general, there should be some mandatory decoration any time you create a method which, in some way, is made to replace a method in a super or subclass.  (decorating overloads isn't as important because they're all defined in the same class)

>> It's better to keep a tight leash on classes and design it such that the only non-final methods are the ones which were made to be non-final. (I prefer to write interfaces and abstract boilerplate classes.  No actual method overriding involved)
> 
> 
> This is more a policy of development style and methodology than anything else.  I don't believe a language should restrict a user unnecesarily. The purpose of any language is to enable them to solve problems they could not solve before, or were very inconvenient to solve before.

Absolutely.  I try to make a point to never forget that programming languages exist solely because both computers and people can read them.

D's built-in syntax for contracts and unit testing brings out the paranoid, fault-tolerance-obsessed monster in me. :)

>> The problem is that, when that explicit annotation is not present, changing method signatures in some base class can cause complete chaos because of all sorts of methods which aren't actually overriding anything.  Nonetheless, it's all legal syntax, and typically compiles just fine.
> 
> Does this happen often?  Once a project reaches a certain level of maturity, I rarely see a need to change a base class method name.

Right.  D does precisely the right thing in this respect. (that is the exact syntax, by the way)

It is a problem is that there's no straightforward way to contractually force an override to call the superclass method it overrides, but that's neither here nor there.

> Look at it this way:
> 
> A method that does not call super.methodName() isn't overriding a method, it is replacing it.  Any call to super.methodName() will
> cause a compile error if super.methodName() does not exist.

This is another idea entirely.  I'm not a fan of C++'s default behaviour being to "hide" the subclass method non-polymorphically.  It's not what most people mean, and it is the cause of a ton of bugs as a result.

>> I think this is a case where it is so easy to do the wrong thing that it is worthwhile to demand that extra bit of explicitness.
> 
> I don't think it is as easy to do wrong as you think, unless there is a bug in the compiler.

Here's an example:

    class Base {
        typedef int value_type;
        void setValue(value_type v) { ... }
    }

    class Derived : Base {
        // does not override because D considers
        // Base.value_type to be distinct from int
        void setValue(int v) { ... }
    }

Now, the question is, is this an error?

Presently, in the eyes of DMD, it is not.  Base defines a method, Derived defines a method with a different signature, the world goes on.

Were I, as a programmer maintaining existing code, to review this, I would suspect that it is a mistake.  At the very least, I'd have to spend some time fishing around to find contextual clues as to whether or not this was intentional. (time's expensive stuff!) If I a bit more rash, I might "fix" it right there on the spot, and potentially create a bug where there was none before.

If 'override' was a required keyword, this could not be a problem. Either the keyword is there and it is a compile-time error, or it is not, and therefore cannot be an override.  One way or another, the maintenance programmer can feel pretty sure he knows what's going on.

>>> When would you *not* override a base class function?  I don't get when you wouldn't want that to happen.
>>
>> This problem arises in C# sometimes.  It basically amounts to wanting to use some method signature which happens to conflict with another method defined in a dark corner of a superclass someplace.  Your method has absolutely nothing to do with that one, save the signature, and you'd rather not be forced to kludge around it by renaming it.
> 
> IMO, if you have this situation, then the work should be split into two separate classes.  No reason to have separate semantics for one method.  It is just one more place where maintenance can go wrong.

Typically, I'm inclined to agree myself.  It's more of a way to kludge over the problem in the interest of saving a perfectly viable design.

 -- andy
July 19, 2004
Hauke Duden wrote:
> Apart from this, checked exceptions are not compatible with interfaces. The whole point of an interface is to abstract from the implementation. But if you have to specify which kinds of errors can occur then you have to foresee any error that could occur in any future implementation - which is impossible, of course.

Huh?  Saying this is akin to saying that interfaces shouldn't specify return values.

July 19, 2004
"Berin Loritsch" wrote ...
> He should have placed a call to super.pause() to have everything working as expected.  However that is done in D.

With respect Berin, may I gently suggest that you go back and read the initial posts on this topic? It's clear that you don't quite grasp the issue at hand. Take a look at those who are supporting the notion of a stricter use of "override":

Matthew
Andy Friesen
tecDruid
Blandger
Derek
Juanjo Álvarez
Vathix
Daniel Horn
Kris

Each of these folks have, to their credit, written a good chunk of D code ~ whereas you apparently have not written any. Of course, you wouldn't know who these people are since you just showed up. Having a "few years" experience and not having run into this issue yourself adds nothing of value to the topic, and the combined experience of the above people likely overshadow that of yours to a reasonably large degree.

If you can comprehend the real issue and come up with a detraction somewhat more constructive than "it would annoy me", that would be most helpful. For example, if you /have/ run into the problems discussed and /have/ found an alternative strategy to deal with them, then let's hear it. Otherwise you're just blowing hot air out yer arse.

Regards;


July 19, 2004
Berin Loritsch wrote:
> Russ Lewis wrote:
> 
>> Berin Loritsch wrote:
>>
>>> When would you *not* override a base class function?  I don't get when you wouldn't want that to happen.
>>
>>
>>
>> Somebody (I forget who) had a problem where he added a pause() function to one of his classes.  However, he later discovered that the class Thread (which, 3 levels back, was a base class of this guy's class) also had a pause() function.  So when some thread code called pause(), it got his pause() function...which definitely does NOT pause the thread.
> 
> 
> So he did not override a method, he replaced the method?
> 
> He should have placed a call to super.pause() to have everything working as expected.  However that is done in D.

The point was that he didn't *realize* that there was a method named pause() in the superclass.

Sure, you can make a valid argument that he could have checked the documentation...but the same problem can occur if the Thread class is later modified to include a new member function, and it turns out that there's a conflicht on that member name.

July 19, 2004
Arcane Jill wrote:

> In article <cdh400$kov$3@digitaldaemon.com>, Berin Loritsch says...
> 
> Berin, I think you've misunderstood. May I take the trouble to explain things?
> First, here's the status quo: The "override" keyword is /not/ compulsory. This
> means that you have a choice of two different ways of writing things. Version
> one:

Please do.

<snip type="examples"/>

Ok now, if I may, can I illustrate my example?

class A
{
    void foo();
}

class B
{
    void foo() { super:foo() };
}

Now, if we change the superclass A's signature to use the boolean we still get a compile error:

class A
{
    void foo(boolean);
}

There is no super:foo() to call.

Also, the examples you gave omitted any type of implementation so it is hard to prove what you would expect to see.

The thing is, it is method replacement if an overriden method never calls the superclass's method.  That is where you will never get a warning or error.

> So how is the designer of class B ever supposed to know that the base class
> signature has changed? Wait for a bug report? "override" gives you a way of
> being notified of the need to change your code (next time you compile the
> source).

Does D somehow always call the superclass's implementation?  I mean sometimes you want to replace a method, but most times you want to extend it and provide more info.

I understand where you are comming from, but using normal class semantics you can still get the desired effect that you want.

> 
> So, "override" is very, very useful, as it can help you find bugs which
> otherwise you might miss for years, and the /absence/ of the "override" keyword
> could be viewed as a bug waiting to happen. So some people have proposed on this
> thread that the keyword be compulsory.

Yuck.  I would much rather see a warning/error if I never called the superclass method--which would have essentially the same effect without having to type a keyword that can very easily be interpreted as clutter.  I prefer my sourcecode to be as clean and clear as possible, extra compulsary keywords add clutter even when they are not needed.


> Another school of thought is that the compiler should always behave /as if/ the
> "override" keyword had been present, so you never actually have to type it.
> However, there are times when you /do/ want to provide a function with the same
> name, but a different signature from, a base class. In D the philosophy seems to
> be to /encourage/ people to do the "right thing", but nonetheless to allow them
> to do something a bit different if they really need to. Which brings me to your
> question:
> 
> 
>>When would you *not* override a base class function?  I don't get when you wouldn't want that to happen.
> 

<snip type="example of method overloading"/>

Well, I know some people who are completely opposed to method overloading, much less operator overloading.  But that really doesn't come to play here.

I suppose a better question would be when would you want method *replacement* as opposed to method *extension*?

If you call super:methodName(), then you are calling a discrete method in a super class--which means that it must exist in order for something to compile correctly.

So this gets the desires of both camps satisfied without using extra keywords.

> 
> So, /sometimes/ you don't want to override, but /usually/ you do, and /usually/
> it's a bug waiting to happen if you don't (because someone might change the base
> class without your knowledge).
> 
> With that in mind, the possibilities at our disposal are:
> 
> (1) the status quo - "override" implies an override; no keyword implies nothing
> at all (so it might or might not be an override)
> 
> (2) as (1), except that the keyword "override" is now compulsory whenever
> overriding.

Yuck.  I don't like that.

> (3) my suggestion - that the behavior currently enabled by the keyword
> "override" be the default behavior, and that, therefore, the keyword itself
> becomes redundant and may be dropped. A side-effect of this is that we'd then
> need a new keyword to do something /other/ than the default.
> 
> (4) require an explicit keyword for each and every possibility.

This is the worst option of the four.  It adds clutter and the real desired meaning gets lost in something your brain naturally filters out due to the number of times it sees it.

(5) have a compiler warning if you override a method but never call the superclass's version.  Conversely if you call a superclass's version and the signature you need is not there, treat it as an error.

Note this does have a corner case that wouldn't be detected:

class A
{
    void foo();
}

class B : A
{
    void foo(boolean);
}

class C : B
{
     void foo() {super:foo();}
}

This would still compile, with the C:foo() calling A:foo() internally--and the foo(boolean) method would not be called from B.

> 
> Changes such as this can be made (by Walter) with ease right now, but post v1.0
> the syntax is supposed to be frozen in concrete, so this is almost our last
> chance to press for changes in syntax. Walter is amenable to suggestions, but
> only if he thinks they're a good idea. (He's not swayed by a mere majority vote
> - you actually have to /convince/ him).

Understood.
July 19, 2004
There are many reasons why you might not want to call the superclass' version of a method.  You can't expect that you will call the supercass method all the time.

Berin Loritsch wrote:
> Arcane Jill wrote:
> 
>> In article <cdh400$kov$3@digitaldaemon.com>, Berin Loritsch says...
>>
>> Berin, I think you've misunderstood. May I take the trouble to explain things?
>> First, here's the status quo: The "override" keyword is /not/ compulsory. This
>> means that you have a choice of two different ways of writing things. Version
>> one:
> 
> 
> Please do.
> 
> <snip type="examples"/>
> 
> Ok now, if I may, can I illustrate my example?
> 
> class A
> {
>     void foo();
> }
> 
> class B
> {
>     void foo() { super:foo() };
> }
> 
> Now, if we change the superclass A's signature to use the boolean we still get a compile error:
> 
> class A
> {
>     void foo(boolean);
> }
> 
> There is no super:foo() to call.
> 
> Also, the examples you gave omitted any type of implementation so it is hard to prove what you would expect to see.
> 
> The thing is, it is method replacement if an overriden method never calls the superclass's method.  That is where you will never get a warning or error.
> 
>> So how is the designer of class B ever supposed to know that the base class
>> signature has changed? Wait for a bug report? "override" gives you a way of
>> being notified of the need to change your code (next time you compile the
>> source).
> 
> 
> Does D somehow always call the superclass's implementation?  I mean sometimes you want to replace a method, but most times you want to extend it and provide more info.
> 
> I understand where you are comming from, but using normal class semantics you can still get the desired effect that you want.
> 
>>
>> So, "override" is very, very useful, as it can help you find bugs which
>> otherwise you might miss for years, and the /absence/ of the "override" keyword
>> could be viewed as a bug waiting to happen. So some people have proposed on this
>> thread that the keyword be compulsory.
> 
> 
> Yuck.  I would much rather see a warning/error if I never called the superclass method--which would have essentially the same effect without having to type a keyword that can very easily be interpreted as clutter.  I prefer my sourcecode to be as clean and clear as possible, extra compulsary keywords add clutter even when they are not needed.
> 
> 
>> Another school of thought is that the compiler should always behave /as if/ the
>> "override" keyword had been present, so you never actually have to type it.
>> However, there are times when you /do/ want to provide a function with the same
>> name, but a different signature from, a base class. In D the philosophy seems to
>> be to /encourage/ people to do the "right thing", but nonetheless to allow them
>> to do something a bit different if they really need to. Which brings me to your
>> question:
>>
>>
>>> When would you *not* override a base class function?  I don't get when you wouldn't want that to happen.
>>
>>
> 
> <snip type="example of method overloading"/>
> 
> Well, I know some people who are completely opposed to method overloading, much less operator overloading.  But that really doesn't come to play here.
> 
> I suppose a better question would be when would you want method *replacement* as opposed to method *extension*?
> 
> If you call super:methodName(), then you are calling a discrete method in a super class--which means that it must exist in order for something to compile correctly.
> 
> So this gets the desires of both camps satisfied without using extra keywords.
> 
>>
>> So, /sometimes/ you don't want to override, but /usually/ you do, and /usually/
>> it's a bug waiting to happen if you don't (because someone might change the base
>> class without your knowledge).
>>
>> With that in mind, the possibilities at our disposal are:
>>
>> (1) the status quo - "override" implies an override; no keyword implies nothing
>> at all (so it might or might not be an override)
>>
>> (2) as (1), except that the keyword "override" is now compulsory whenever
>> overriding.
> 
> 
> Yuck.  I don't like that.
> 
>> (3) my suggestion - that the behavior currently enabled by the keyword
>> "override" be the default behavior, and that, therefore, the keyword itself
>> becomes redundant and may be dropped. A side-effect of this is that we'd then
>> need a new keyword to do something /other/ than the default.
>>
>> (4) require an explicit keyword for each and every possibility.
> 
> 
> This is the worst option of the four.  It adds clutter and the real desired meaning gets lost in something your brain naturally filters out due to the number of times it sees it.
> 
> (5) have a compiler warning if you override a method but never call the superclass's version.  Conversely if you call a superclass's version and the signature you need is not there, treat it as an error.
> 
> Note this does have a corner case that wouldn't be detected:
> 
> class A
> {
>     void foo();
> }
> 
> class B : A
> {
>     void foo(boolean);
> }
> 
> class C : B
> {
>      void foo() {super:foo();}
> }
> 
> This would still compile, with the C:foo() calling A:foo() internally--and the foo(boolean) method would not be called from B.
> 
>>
>> Changes such as this can be made (by Walter) with ease right now, but post v1.0
>> the syntax is supposed to be frozen in concrete, so this is almost our last
>> chance to press for changes in syntax. Walter is amenable to suggestions, but
>> only if he thinks they're a good idea. (He's not swayed by a mere majority vote
>> - you actually have to /convince/ him).
> 
> 
> Understood.

July 19, 2004
In article <cdh8fs$mo2$1@digitaldaemon.com>, Andy Friesen says...
>
>I think it's a good thing that a class designer be able to decide which methods can and can't be overridden.  D does provide this, which makes me a happy camper either way, but I prefer the explicit annotation.

D does provide this - but with the keyword "final", not the keyword "override". Of course, you knew that.


>Explicitly decorating a function as being overridable serves as a positive assertion that you want it to be so.  This carries with it a piece of your notion of how the class ought to be used: The class's own definition explicitly says "I was made to be subclassed in precisely this manner."
>
>Negatives aren't as strong because they mean either yes or "no but I forgot to say so".

Indeed, that's what not using the keyword "final" means, but this is unrelated to the use of "override".


>I think, in general, there should be some mandatory decoration any time you create a method which, in some way, is made to replace a method in a super or subclass.  (decorating overloads isn't as important because they're all defined in the same class)

Okay, /now/ you're talking about "override".



July 19, 2004
>There are many reasons why you might not want to call the superclass' version of a method.  You can't expect that you will call the supercass method all the time.

Well yeah! Like, who in their right mind would want to call Object.opCmp() from
within SomeOtherClass.opCmp()? (Or indeed, at all!)

And why on Earth would MyClass.toString() want to call Object.toString()?

What's with all this baseclass version stuff? Where did that come from? It doesn't seem to me to have anything to do with what anyone else is discussing.

Jill


July 19, 2004
I am enjoying the conversation BTW.

Andy Friesen wrote:

> It is a problem is that there's no straightforward way to contractually
> force an override to call the superclass method it overrides, but that's
> neither here nor there.

I think requiring this is more elegant than forcing a keyword to be used everywhere.  More on that later.

> Here's an example:
>
>     class Base {
>         typedef int value_type;
>         void setValue(value_type v) { ... }
>     }
>
>     class Derived : Base {
>         // does not override because D considers
>         // Base.value_type to be distinct from int
>         void setValue(int v) { ... }
>     }
>
> Now, the question is, is this an error?
>
> Presently, in the eyes of DMD, it is not.  Base defines a method,
> Derived defines a method with a different signature, the world goes on.

:)  In D, value_type and int are two different things.  In C++ they are
the same thing--so this is something that can be a source of confusion.
Esp. if there is an implicit conversion from int to value_type (the C++
way).

I can understand there being an issue here, and the possibility of requiring the override keyword in this case.


On requiring the keyword all the time:
-------------------------------------

I am very much not in favor of this approach.  The reason is the way our
brains work.  When we see something repeated over and over again, it comes accross as noise which the brain attempts to filter out.  It is looking for the differences to see what the problem might be.  When something is repeated over and over and over it has less significance to the brain's powers of perception.  When you have keywords of similar size in place to explicitly declare the intent then I know I personally
wouldn't notice them as quickly.

Take for instance the textbook scoping error:

class Example
{
    Label m_label;

    void display()
    {
        Label m_label = new Label("see");
    }
}

Most people, even experienced developers, can miss it.  Its because seeing the word "Label" starts looking like noise, so the brain just
throws out the one that redeclares the variable within the method.

The same effect can happen if you require a keyword to be used in each and every method.  Methods are fairly plentious.

-- 

"Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning."
                - Rich Cook
July 19, 2004
Kris wrote:

> "Berin Loritsch" wrote ...
> 
>>He should have placed a call to super.pause() to have everything working
>>as expected.  However that is done in D.
> 
> 
> With respect Berin, may I gently suggest that you go back and read the
> initial posts on this topic? It's clear that you don't quite grasp the issue
> at hand. Take a look at those who are supporting the notion of a stricter
> use of "override":
> 
> Matthew
> Andy Friesen
> tecDruid
> Blandger
> Derek
> Juanjo Álvarez
> Vathix
> Daniel Horn
> Kris

Ok.