January 23, 2007
Sean Kelly wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Sean Kelly wrote:
>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>> kris wrote:
>>>> [snip]
>>>>> In short, it appears the example exhibits some poor practice (overriding private methods), is somewhat misleading (one certainly *hopes* private cannot be seen beyond module-scope), and discusses how to make "final" mean something quite other than final.
>>>>
>>>> I agree about the misleading part, but I don't think that overriding private methods is poor practice. In fact I think it's rich practice :o). See e.g. http://www.gotw.ca/publications/mill18.htm.
>>>
>>> It's a good design approach, but there's no reason the virtual methods must be private--they could be protected as well.  One could argue that the design is cleaner with the virtual methods private, but since the methods must be overridden by the derived class it's not like any protection attributes are being maintained anyway.  Isn't this a current topic of discussion on comp.l.c++.m? :-)
>>
>> There is a big difference between private and protected. Private means that later-added code cannot call the method, period. It could be said that private is "distantly more private" than both protected and public because both of the latter allow access by unbounded amounts of code.
>>
>> So there is indeed something interesting by being required to implement something that you're not allowed to call. Something like Shirley Temple acting in movies she was too young to be allowed to watch :o).
> 
> But you can call it, or even change its visibility:
> 
> class Base
> {
> private:
>     virtual void fn() = 0;
> };
> 
> class Derived : Base
> {
> public:
>      virtual void fn() {}
>     void call() { fn(); }
> };
> 
> Sure, you can't call it through Base::fn(), but... :-)

Oh, my hope was that D disallows republicizing private functions :o(. Spectacular failure to provide a great feature...

Andrei
January 23, 2007
Steve Horne wrote:
[snip]

> And adding a new private member to a base class should not
> break any derived classes that might happen to already use the same
> signature for a (private or public) method, especially since you may
> have no control or even knowledge of those derived classes.

Given that, I'd imagine you'd be a proponent of making 'override' a required keyword? After all, not requiring it will likely lead to the same type of problem when a base-class method is removed.

Yet, judging by past record, override is unlikely to ever be required.
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Sean Kelly wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Sean Kelly wrote:
>>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>>> kris wrote:
>>>>> [snip]
>>>>>> In short, it appears the example exhibits some poor practice (overriding private methods), is somewhat misleading (one certainly *hopes* private cannot be seen beyond module-scope), and discusses how to make "final" mean something quite other than final.
>>>>>
>>>>> I agree about the misleading part, but I don't think that overriding private methods is poor practice. In fact I think it's rich practice :o). See e.g. http://www.gotw.ca/publications/mill18.htm.
>>>>
>>>> It's a good design approach, but there's no reason the virtual methods must be private--they could be protected as well.  One could argue that the design is cleaner with the virtual methods private, but since the methods must be overridden by the derived class it's not like any protection attributes are being maintained anyway.  Isn't this a current topic of discussion on comp.l.c++.m? :-)
>>>
>>> There is a big difference between private and protected. Private means that later-added code cannot call the method, period. It could be said that private is "distantly more private" than both protected and public because both of the latter allow access by unbounded amounts of code.
>>>
>>> So there is indeed something interesting by being required to implement something that you're not allowed to call. Something like Shirley Temple acting in movies she was too young to be allowed to watch :o).
>>
>> But you can call it, or even change its visibility:
>>
>> class Base
>> {
>> private:
>>     virtual void fn() = 0;
>> };
>>
>> class Derived : Base
>> {
>> public:
>>      virtual void fn() {}
>>     void call() { fn(); }
>> };
>>
>> Sure, you can't call it through Base::fn(), but... :-)
> 
> Oh, my hope was that D disallows republicizing private functions :o(. Spectacular failure to provide a great feature...

I think it effectively does, since private functions can not be overridden.  The above was C++ (I should have labeled the code).


Sean
January 23, 2007
kris wrote:
> Sean Kelly wrote:
>> kris wrote:
>>
>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>
>>>> kris wrote:
>>>> [snip]
>>>> I agree about the misleading part, but I don't think that overriding private methods is poor practice. In fact I think it's rich practice :o). See e.g. http://www.gotw.ca/publications/mill18.htm.
>>>>
>>>> Andrei
>>>
>>>
>>> Design philosophy aside, what should be done about the issues with "final" itself?
>>
>>
>> I think the current design is consistent but potentially confusing.  If a function can be virtual (ie. if it is not private) then "final" controls whether it can be overridden.  So making a private function final is meaningless because it cannot be overridden--in this case, "final" is simply ignored.
> 
> Fair enough. Then the compiler should be a tad smarter about disallowing 'stupid' combinations of attributes. This applies to many other attributes, not just final. People /will/ use whatever combination they're allowed to, and the doc appears to encourage them to do so.

The spec does this in a number of places.  For example:

const auto static auto const auto i = 5; // what is i?
January 23, 2007
Sean Kelly wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Sean Kelly wrote:
>>> class Base
>>> {
>>> private:
>>>     virtual void fn() = 0;
>>> };
>>>
>>> class Derived : Base
>>> {
>>> public:
>>>      virtual void fn() {}
>>>     void call() { fn(); }
>>> };
>>>
>>> Sure, you can't call it through Base::fn(), but... :-)
>>
>> Oh, my hope was that D disallows republicizing private functions :o(. Spectacular failure to provide a great feature...
> 
> I think it effectively does, since private functions can not be overridden.  The above was C++ (I should have labeled the code).

That's great news. The semicolons should have informed me... oh, and wait, there's no "virtual" in D... :o)

Andrei
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Sean Kelly wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Sean Kelly wrote:
>>>> class Base
>>>> {
>>>> private:
>>>>     virtual void fn() = 0;
>>>> };
>>>>
>>>> class Derived : Base
>>>> {
>>>> public:
>>>>      virtual void fn() {}
>>>>     void call() { fn(); }
>>>> };
>>>>
>>>> Sure, you can't call it through Base::fn(), but... :-)
>>>
>>> Oh, my hope was that D disallows republicizing private functions :o(. Spectacular failure to provide a great feature...
>>
>> I think it effectively does, since private functions can not be overridden.  The above was C++ (I should have labeled the code).
> 
> That's great news. The semicolons should have informed me... oh, and wait, there's no "virtual" in D... :o)

And there's definitely no '= 0' at the end of method declarations. Oh, and his comment at the end mentioned 'Base::fn()' instead of 'Base.fn()' :)
January 23, 2007
On Tue, 23 Jan 2007 00:26:10 -0800, kris <foo@bar.com> wrote:

>Steve Horne wrote:
>[snip]
>
>> And adding a new private member to a base class should not
>> break any derived classes that might happen to already use the same
>> signature for a (private or public) method, especially since you may
>> have no control or even knowledge of those derived classes.
>
>Given that, I'd imagine you'd be a proponent of making 'override' a required keyword? After all, not requiring it will likely lead to the same type of problem when a base-class method is removed.
>
>Yet, judging by past record, override is unlikely to ever be required.

Override should only be specified when the intent is to override, IMO.

If adding a new public/protected method to a base class results in its accidentally being overridden by a pre-existing conflicting derived-class method, clearly that's bad. So...

1. Specifying override on a method that doesn't override any base
   class method should be an error.
2. Failing to specify override on a method that does override a base
   class public/protected method should be an error.

I thought that was what D does anyway, and for that matter that it was the whole point of the override keyword - but, as I said, I'm more in C++ mode ATM (and haven't been using D that long anyway).

Presumably removal of an overridden base-class method would be covered by case 1, which is why you are saying it should be required, and therefore I assume this case 1 error doesn't occur. Which gets a reading on my odd-ometer.

Mind you, removing a public/protected interface from a published class should be a pretty unusual thing to do. Getting people dependent on an interface and then just taking it away without warning is more than a bit dodgy. The possibility of problems shouldn't really come as a surprise.

It's similar to the rule for COM interfaces - extending is OK, different implementations OK, but compatibility with previously published interfaces should be maintained (though the main breaker of that rule seems to be Microsoft itself).

When adding new methods creates problems, there is genuine reason why you wouldn't necessarily anticipate the problems - you can't necessarily know which new method signatures would be safe and which would cause conflicts. So case 2 above is much more important to me than case 1, since it catches non-obvious errors rather than errors I should have anticipated.

My main reason for case 1 is that programmers shouldn't add override flags to every single method just to save thinking about it, since it defeats the whole point of the keyword. But it's just so obviously grossly bad style anyway, like not bothering with indentation or calling your variable var1, var2, var3 and so on.


Going off on a tangent, a way of saying 'OK, this is the same signature as a base class method, but this is independent, and gets a separate slot in the virtual table' might be a good idea. Perhaps an alternate application of the 'new' keyword. Or maybe there already is a flag for this, and I forgot.

The idea is that, when a derived class developer gets a conflict with a new base class interface, there's a quick (if slightly dirty) fix. The derived class can keep its (possibly also published) interface intact. Anyone needing the base class version can use a call notation indicating that, or else cast to the base class - less than ideal, but maybe better than forcing the derived class developers into renaming and refactoring, and the resulting interface change.

-- 
Remove 'wants' and 'nospam' from e-mail.
January 23, 2007
On Tue, 23 Jan 2007 12:08:39 +0100, Frits van Bommel wrote:

> 
> And there's definitely no '= 0' at the end of method declarations. Oh, and his comment at the end mentioned 'Base::fn()' instead of 'Base.fn()' :)


Yeah!  Rub it in...  lol! :D

-JJR
January 23, 2007
Steve Horne wrote:
> On Tue, 23 Jan 2007 00:26:10 -0800, kris <foo@bar.com> wrote:
> 
> 
>>Steve Horne wrote:
>>[snip]
>>
>>
>>>And adding a new private member to a base class should not
>>>break any derived classes that might happen to already use the same
>>>signature for a (private or public) method, especially since you may
>>>have no control or even knowledge of those derived classes.
>>
>>Given that, I'd imagine you'd be a proponent of making 'override' a required keyword? After all, not requiring it will likely lead to the same type of problem when a base-class method is removed.
>>
>>Yet, judging by past record, override is unlikely to ever be required.
> 
> 
> Override should only be specified when the intent is to override, IMO.
> 
> If adding a new public/protected method to a base class results in its
> accidentally being overridden by a pre-existing conflicting
> derived-class method, clearly that's bad. So...
> 
> 1. Specifying override on a method that doesn't override any base
>    class method should be an error.
> 2. Failing to specify override on a method that does override a base
>    class public/protected method should be an error.
> 
> I thought that was what D does anyway, and for that matter that it was
> the whole point of the override keyword 
[snip]

(1) does generate an error, but (2) has never generated one, and requests to make it do so have met with silence from W for years :)

Everything else you say I agree with, and thanks for taking the time to respond in such detail.

- Kris
January 24, 2007
On Tue, 23 Jan 2007 09:20:18 -0800, kris <foo@bar.com> wrote:

>Steve Horne wrote:

>> 1. Specifying override on a method that doesn't override any base
>>    class method should be an error.
>> 2. Failing to specify override on a method that does override a base
>>    class public/protected method should be an error.

>(1) does generate an error, but (2) has never generated one, and requests to make it do so have met with silence from W for years :)

Ah - ok. I'm not so sure the override modifier has much value, done this way.

I guess I agree - it looks like a missed opportunity. I guess the trouble is that tightening up the rules would be big breaking change. Easy to fix, but a lot of fixing needed.

Oh well.

-- 
Remove 'wants' and 'nospam' from e-mail.
1 2
Next ›   Last »