March 19, 2012
Because of the syntax sugar.

On Mon, Mar 19, 2012 at 8:26 PM, deadalnix <deadalnix@gmail.com> wrote:
> Le 19/03/2012 14:38, Gor Gyolchanyan a écrit :
>
>> Having a final class is conceptually different from having a class with only final methods. You can legitimately inherit from a class with no virtual methods and add to its interface and implement other methods using its final ones. The final class concept is extremely useful when you just don't want to be inherited from. For instance, Your class may be closely tied to an implementation and inheriting from it would wreck the implementation.
>>
>
> It looks like a bad usage of inheritance. If you want to use these methods, why not use composition ?
>
> It make no sense to use such an inherited class in a polymorphic context, so why use inheritance at all ?



-- 
Bye,
Gor Gyolchanyan.
March 19, 2012
deadalnix wrote:
> It looks like a bad usage of inheritance. If you want to use these methods, why not use composition ?
>
> It make no sense to use such an inherited class in a polymorphic context, so why use inheritance at all ?

Am I missing something about what you're saying? Having a final
class is completely different than locking up it's functions:

   abstruct class Actor
   {
     void create() {}
     void update() {}
   }

   class Ship : Actor
   {
     final void create() {}
     final void update() {}
     final void fire() {}
   }

   class MotherShip : Ship
   {
     final void fireMissle() {}
   }

   void main() {
     Actor[] actors = [
         new Ship();
         new MotherShip();
       ];

     foreach (actor; actors) {
       actor.fire();
     }
   }

If Ship was final simply because all it's methods where, then you
couldn't inherit it's functionality into MotherShip.


March 19, 2012
Le 19/03/2012 18:41, F i L a écrit :
> deadalnix wrote:
>> It looks like a bad usage of inheritance. If you want to use these
>> methods, why not use composition ?
>>
>> It make no sense to use such an inherited class in a polymorphic
>> context, so why use inheritance at all ?
>
> Am I missing something about what you're saying? Having a final
> class is completely different than locking up it's functions:
>
> abstruct class Actor
> {
> void create() {}
> void update() {}
> }
>
> class Ship : Actor
> {
> final void create() {}
> final void update() {}
> final void fire() {}
> }
>
> class MotherShip : Ship
> {
> final void fireMissle() {}
> }
>
> void main() {
> Actor[] actors = [
> new Ship();
> new MotherShip();
> ];
>
> foreach (actor; actors) {
> actor.fire();
> }
> }
>
> If Ship was final simply because all it's methods where, then you
> couldn't inherit it's functionality into MotherShip.
>
>

That is totally broken design. The fact that mothership inherit from ship is a pretty good example of misusing inheritance. The fireMissle is useless unless you KNOW that you are manipulating a MotherShip, so you totally break all the abstraction the OOP could provide.
March 19, 2012
Le 19/03/2012 17:28, Gor Gyolchanyan a écrit :
> Because of the syntax sugar.
>

This is exactly the type of behavior that a language should discourage.
March 19, 2012
Le 18/03/2012 22:36, James Miller a écrit :
> On 19 March 2012 06:41, David Nadlinger<see@klickverbot.at>  wrote:
>> On Sunday, 18 March 2012 at 17:24:15 UTC, F i L wrote:
>>>
>>> […] I know LDC has a  LTO flag.
>>
>>
>> Unfortunately it doesn't (-O4/-O5 are defunct), but working on seamless LTO
>> integration (and better optimization pass scheduling in general) would be
>> low-hanging fruit for anybody wanting to join LDC development.
>>
>> David
>
> I think that simply adding a `virtual` keyword that explicitly makes
> things virtual, even if they would otherwise be final, makes sense.
> Keep all the current semantics the same, relegate use of `virtual` to
> the 'advanced' section of D usage, everybody is happy.
>
> I'm with Manu in the case of "I don't trust the compiler". I'm
> perfectly happy for the compile to optimize short sections of code
> that I probably could optimize myself, but its not much of an issue,
> but I am reluctant to rely on the tooling to make decisions for me.
> For small programs, where it doesn't matter if it's half as fast as it
> could be, but that just means 2ms vs 1ms, I don't care. But in
> intensive programs, then I want to be sure that the compiler will do
> what I want.
>
> --
> James Miller

+1
March 19, 2012
deadalnix wrote:
> That is totally broken design. The fact that mothership inherit from ship is a pretty good example of misusing inheritance. The fireMissle is useless unless you KNOW that you are manipulating a MotherShip, so you totally break all the abstraction the OOP could provide.

Other objects can contain references to MotherShip types directly, while the main update loop works with the base type. Or, perhaps more relevant, an object could execute "fire()" on a list of Ships, which MotherShip can be a part of because it IS a Ship, regardless if weather it can overwrite Ship's functions or not. I can't imagine a different way of defining this relationship short of inheriting from a common interface which would require duplicating the fire() function in both types (given that fire() is designed to ensure common behavior among all Ship types).

This is not a broken concept at all. I'm always open to different ideas, but I'm fairly surprised you're arguing this case. Being able to extend a type, even when the extensions are entirely additive, is a fundamental principle of OOP design.
March 19, 2012
On 3/18/2012 9:25 AM, FeepingCreature wrote:
> See subject.

When proposing a new feature, the question is not "why not?". The question is what compelling capability does it bring.
March 19, 2012
Le 19/03/2012 21:39, F i L a écrit :
> deadalnix wrote:
>> That is totally broken design. The fact that mothership inherit from
>> ship is a pretty good example of misusing inheritance. The fireMissle
>> is useless unless you KNOW that you are manipulating a MotherShip, so
>> you totally break all the abstraction the OOP could provide.
>
> Other objects can contain references to MotherShip types directly, while
> the main update loop works with the base type. Or, perhaps more
> relevant, an object could execute "fire()" on a list of Ships, which
> MotherShip can be a part of because it IS a Ship, regardless if weather
> it can overwrite Ship's functions or not. I can't imagine a different
> way of defining this relationship short of inheriting from a common
> interface which would require duplicating the fire() function in both
> types (given that fire() is designed to ensure common behavior among all
> Ship types).
>

As all functionnality of a Ship are final, you basically ends up with a mother ship that is a ship and then have some other function that are de facto separated and unreachable from ship. Separation of concerns tells us that this should be 2 different objects.

> This is not a broken concept at all. I'm always open to different ideas,
> but I'm fairly surprised you're arguing this case. Being able to extend
> a type, even when the extensions are entirely additive, is a fundamental
> principle of OOP design.

As teha ddition of MotherShip to Ship are orthogonal, I would argue that mothership functionality is better suited for its own class/struct/whatever, and agregated with a ship.

The whole « is a » thing is largely misunderstood. See http://www.objectmentor.com/resources/articles/lsp.pdf for example.
March 19, 2012
Le 19/03/2012 21:43, Walter Bright a écrit :
> On 3/18/2012 9:25 AM, FeepingCreature wrote:
>> See subject.
>
> When proposing a new feature, the question is not "why not?". The
> question is what compelling capability does it bring.

In this case, this isn't really a feature, but more syntaxic sugar. Anyway, I don't think this is that important.
March 19, 2012
On 3/19/12 5:11 PM, deadalnix wrote:
> Le 19/03/2012 21:39, F i L a écrit :
>> deadalnix wrote:
>>> That is totally broken design. The fact that mothership inherit from
>>> ship is a pretty good example of misusing inheritance. The fireMissle
>>> is useless unless you KNOW that you are manipulating a MotherShip, so
>>> you totally break all the abstraction the OOP could provide.
>>
>> Other objects can contain references to MotherShip types directly, while
>> the main update loop works with the base type. Or, perhaps more
>> relevant, an object could execute "fire()" on a list of Ships, which
>> MotherShip can be a part of because it IS a Ship, regardless if weather
>> it can overwrite Ship's functions or not. I can't imagine a different
>> way of defining this relationship short of inheriting from a common
>> interface which would require duplicating the fire() function in both
>> types (given that fire() is designed to ensure common behavior among all
>> Ship types).
>>
>
> As all functionnality of a Ship are final, you basically ends up with a
> mother ship that is a ship and then have some other function that are de
> facto separated and unreachable from ship. Separation of concerns tells
> us that this should be 2 different objects.
>
>> This is not a broken concept at all. I'm always open to different ideas,
>> but I'm fairly surprised you're arguing this case. Being able to extend
>> a type, even when the extensions are entirely additive, is a fundamental
>> principle of OOP design.
>
> As teha ddition of MotherShip to Ship are orthogonal, I would argue that
> mothership functionality is better suited for its own
> class/struct/whatever, and agregated with a ship.
>
> The whole « is a » thing is largely misunderstood. See
> http://www.objectmentor.com/resources/articles/lsp.pdf for example.

I agree 100%. Inheriting to extend is borderline fallacious.

Regarding the matter at hand, it's true that the interplay of final class with final methods has an odd and less useful corner case, but I don't think it's worth worrying about it.


Andrei