June 06, 2013
On Wednesday, 5 June 2013 at 22:03:05 UTC, Walter Bright wrote:

> We can do an upgrade path as follows:
>
> 1. Introduce 'virtual' storage class. 'virtual' not only means a method is virtual, but it is an *introducing* virtual, i.e. it starts a new vtbl[] entry even if there's a virtual of the same name in the base classes. This means that functions marked 'virtual' do not override functions marked 'virtual'.

Note that 'new' modifier in C# is applicable not only to virtual methods (MS calls it "name hiding"). Not using 'new' when hiding a public member is a warning.

References:
http://msdn.microsoft.com/en-us/library/vstudio/435f1dw2.aspx
http://msdn.microsoft.com/en-us/library/aa691135(v=vs.71).aspx
http://msdn.microsoft.com/en-us/library/aa645767(v=vs.71).aspx

Some points from limited personal experience:

1. Private final methods in D can hide base methods. That's *useful*. Don't try to change that.
2. Public final methods in D cannot be hidden. That's been a problem for me and other people.
3. I've seen 'new' on final methods in C# in practice and used it myself. I've never seen virtual methods being hidden and never needed that myself.

>
> 2. Issue a warning if a function overrides a function that is not marked 'virtual'.
>
> 3. Deprecate (2).
>
> 4. Error (2), and make non-virtual the default.
June 06, 2013
On Thursday, 6 June 2013 at 01:08:36 UTC, deadalnix wrote:
> On Thursday, 6 June 2013 at 01:00:36 UTC, Steven Schveighoffer wrote:
>> This was circa 2003.  Look at the state of Java from then.  And also consider that when the *decision* was made to make non-virtual the default, was considerably before then.
>>
>> -Steve
>
> This is why I wrote that this may have been true in the past. Nevertheless, it is completely false today.
>
> History also showed us that C# introduced way to revirtualize method, for several purposes like mock. We can't simple take this argument and don't look at it with the light of history.
>
> The history shows that out of 3 point, only one remains valid, and this is the one about properties. Ironically, this is the one that do not apply to D (in its current shape) as we don't have an proper property.

As I mentioned before, given that I speak more than really using D for anything, my opinion should not count.

In C#'s case, which is similar to D, you not only have a VM, but also ahead of time compilation.

Virtual by default wins when you have a VM that can do devirtualization.

When doing static compilation, even with LTO, you are limited in what you can do, specially if generating dynamic libraries.

I complain a lot about limited choice in Java native compilers, but given the language semantics, a JVM with JIT is actually faster, hence why no one bothers except for a few niche cases, other being the price for such compilers.

So a good question would be in the languages that have native compilers as canonical implementation and use virtual by default, how fast can method invocations be done. Ada, Eiffel, Dylan, Lisp, Go, ...

--
Paulo



June 06, 2013
On Thursday, 6 June 2013 at 07:43:30 UTC, Paulo Pinto wrote:
> As I mentioned before, given that I speak more than really using D for anything, my opinion should not count.
>
> In C#'s case, which is similar to D, you not only have a VM, but also ahead of time compilation.
>
> Virtual by default wins when you have a VM that can do devirtualization.
>

devirtualization is a link time problem, not a runtime one. We can do that in D (except when it come to shared objects) and I even proposed solutions to do so.

revirtualization, however, can only be done with a JIT compiler. And it is done in C# . They had this option, D won't have it.

> When doing static compilation, even with LTO, you are limited in what you can do, specially if generating dynamic libraries.
>

Exact, but this is nothing specific to virtual. shared library come at a cost, as the call is opaque to the compiler. It has to assume the worse and must disable most optimizations anyway. You are trying to pose a bandage on a wooden leg.
June 06, 2013
On Thursday, 6 June 2013 at 05:52:28 UTC, Jonathan M Davis wrote:

> 1. 'virtual' means a method is an "introducing" one.
> 2. 'override' means override with a non-final function.
> 3. 'final override' means a method overrides a base virtual function with a final function.
> 4. 'final' by itself and none both mean final and non-overriding.

I like the 'final override', it is more natural.

What about case when you want to introduce new final method of the same name as already existing final method in base (c# uses 'new' for this)

class Base { final void foo () }
class Derived : Base { new void foo () }

what would be in place of 'new' in D?
June 06, 2013
On Thursday, June 06, 2013 10:42:26 Michal Minich wrote:
> On Thursday, 6 June 2013 at 05:52:28 UTC, Jonathan M Davis wrote:
> > 1. 'virtual' means a method is an "introducing" one.
> > 2. 'override' means override with a non-final function.
> > 3. 'final override' means a method overrides a base virtual
> > function with a final function.
> > 4. 'final' by itself and none both mean final and
> > non-overriding.
> 
> I like the 'final override', it is more natural.
> 
> What about case when you want to introduce new final method of the same name as already existing final method in base (c# uses 'new' for this)
> 
> class Base { final void foo () }
> class Derived : Base { new void foo () }
> 
> what would be in place of 'new' in D?

We could probably use new to mean the same thing, but I confess that even allowing this seems incredibly bad to me. You end up with a base class function which isn't being overidden looking like it's being overriden in a derived class. And even if it's obvious when look at Derived's declaration thanks to the new, anything which is derived from Derived would just be marked with override. So, it would be incredibly easy to think that calling Base.foo would call Derived.foo or the foo function of the class derived from Derived.

So, certainly my initial reaction is to say that because Base.foo was marked with final, it shouldn't be possible for any of its derived classes to have a function with the same signature.

- Jonathan M Davis
June 06, 2013
> On Thursday, June 06, 2013 10:42:26 Michal Minich wrote:
>> On Thursday, 6 June 2013 at 05:52:28 UTC, Jonathan M Davis

>> What about case when you want to introduce new final method of
>> the same name as already existing final method in base (c# uses
>> 'new' for this)
>> 
>> class Base { final void foo () }
>> class Derived : Base { new void foo () }
>> 
>> what would be in place of 'new' in D?
>
> We could probably use new to mean the same thing, but I confess that even
> allowing this seems incredibly bad to me. You end up with a base class
> function which isn't being overidden looking like it's being overriden in a
> derived class. And even if it's obvious when look at Derived's declaration
> thanks to the new, anything which is derived from Derived would just be marked
> with override. So, it would be incredibly easy to think that calling Base.foo
> would call Derived.foo or the foo function of the class derived from Derived.
>
> So, certainly my initial reaction is to say that because Base.foo was marked
> with final, it shouldn't be possible for any of its derived classes to have a
> function with the same signature.

That can cause problem for author of base class - if he add any final method, he can break derived classes he may not know of. Example - if you update your external lib you are using in your project, and it happens that new version of some base has 'search' final function added, and you happen to have fn with same name in in your derived, you must now rename all your usages of 'search' function... (i would be preferable if you could just add new on in your derived class 'search').

This problems are more common in languages as C# where OOP is more frequently used as in D. Also this issue will be more frequent in D with final as default, because to this time virtual method were more common - and they don't have this issue as they have 'override' behavior. 'new' would be orthogonal to 'override' for final functions.

virutals can be overridden
finals can be newed

I think it is very clearly explained in pasted specification in comment http://forum.dlang.org/post/op.wx8biyx7eav7ka@stevens-macbook-pro.local
June 06, 2013
On Thu, Jun 06, 2013 at 11:16:01AM +0200, Michal Minich wrote:
> >On Thursday, June 06, 2013 10:42:26 Michal Minich wrote:
> >>On Thursday, 6 June 2013 at 05:52:28 UTC, Jonathan M Davis
> 
> >>What about case when you want to introduce new final method of the same name as already existing final method in base (c# uses 'new' for this)
> >>
> >>class Base { final void foo () }
> >>class Derived : Base { new void foo () }
> >>
> >>what would be in place of 'new' in D?
> >
> >We could probably use new to mean the same thing, but I confess that even allowing this seems incredibly bad to me. You end up with a base class function which isn't being overidden looking like it's being overriden in a derived class. And even if it's obvious when look at Derived's declaration thanks to the new, anything which is derived from Derived would just be marked with override. So, it would be incredibly easy to think that calling Base.foo would call Derived.foo or the foo function of the class derived from Derived.
> >
> >So, certainly my initial reaction is to say that because Base.foo was marked with final, it shouldn't be possible for any of its derived classes to have a function with the same signature.
> 
> That can cause problem for author of base class - if he add any final method, he can break derived classes he may not know of. Example - if you update your external lib you are using in your project, and it happens that new version of some base has 'search' final function added, and you happen to have fn with same name in in your derived, you must now rename all your usages of 'search' function... (i would be preferable if you could just add new on in your derived class 'search').
[...]

Wait, why would this be a problem? D already requires that you specify 'override' if you're overriding a base class method. Since final methods cannot be overridden, if the derived class declares a method of the same signature as a base class method, it should be obvious that it's *not* overriding anything. There's no need to use 'new'.


T

-- 
Nearly all men can stand adversity, but if you want to test a man's character, give him power. -- Abraham Lincoln
June 06, 2013
On 06/06/2013 04:17 PM, H. S. Teoh wrote:
> Wait, why would this be a problem? D already requires that you specify 'override' if you're overriding a base class method. Since final methods cannot be overridden, if the derived class declares a method of the same signature as a base class method, it should be obvious that it's *not* overriding anything. There's no need to use 'new'.

The rationale is given in Steven's earlier post: http://forum.dlang.org/post/op.wx8biyx7eav7ka@stevens-macbook-pro.local

June 06, 2013
On Wed, 05 Jun 2013 21:14:08 -0400, Jonathan M Davis <jmdavisProg@gmx.com> wrote:

> On Wednesday, June 05, 2013 17:49:17 Walter Bright wrote:
>> I think we accomplish this in a simpler way:
>>
>> 1. 'virtual' means a method is an "introducing" one.
>> 2. 'override' means a method overrides a base virtual function with a final
>> function.
>> 3. 'override virtual' means override with a non-final function.
>> 4. none means final and non-overriding.
>
> I would have expected something more like
>
> 1. 'virtual' means a method is an "introducing" one.
> 2. 'override' means override with a non-final function.
> 3. 'final override' means a method overrides a base virtual function with a
> final function.
> 4. 'final' by itself both mean final and non-overriding.

I agree, I think it can be expressed by answering two questions:

1. Do you want to participate in a base class' virtual call
2. Do you want to allow derived classes to participate in the virtual call.

If you answer yes to 1, add override, otherwise (or if there is no base method), add nothing (in C# answering no, you should add 'new' if there is an existing base function)
If you answer yes to 2, add virtual, otherwise, add final.

But there are a couple of defaults I think are important to establish:
- With no specific storage classes, the default is non-overriding, final.
- When override is specified, the default for allowing participation up the chain switches to virtual.  So explicitly stating virtual is OK but redundant.  This is where Walter's idea differs.  And I think it makes sense, when a base class has a virtual call, the overwhelming default is to continue the virtual chain.

So when answering the original questions [optional]:

1 = yes, 2 = yes, use override [virtual]
1 = no*, 2 = yes, use virtual
1 = yes 2 = no, use override final
1 = no*, 2 = no, use [final]

* note: if no base class virtual function exists, then the answer to question 1 is always no, and override is an error.

The one deviation from the current "require override" behavior of the compiler exposes the following sequence:

1. Base class does not define foo, derived class defines foo, virtual or not.
2. Base class adds foo as virtual

Currently, this will cause an error in the compiler.  With this new scheme, the compiler silently accepts this as two unrelated functions, because override is not used.  Arguably this is the correct choice, it is what the author of derived originally intended, and C# implies this by compiling, but it does give a warning.

Since we would have no keyword to indicate "non-overriding", a warning is not possible, since there's no explicit way to say "I'm not overriding".  I would argue that putting 'new' there doesn't add much, you are unlikely to change your method's semantics to match that of the base class' new method.  What the C# explanation I quoted seems to miss is that it's not the author of the derived class who is affected, it's the USER of the derived class.  The confusion is for usage, not semantics, and that can be a problem.

Admittedly, the case above should be rather rare.  Perhaps the compiler can have a switch which identifies all the places where functions are masked?  I would like to see the switch be configurable as to which packages to do this for.

-Steve
June 06, 2013
On Thursday, 6 June 2013 at 01:08:36 UTC, deadalnix wrote:
> This is why I wrote that this may have been true in the past. Nevertheless, it is completely false today.

C# often does not inline virtual methods, and even if it can inline them there's still an overhead. This (2008) article goes into depth about how it handles it: www.codeproject.com/Articles/25801/JIT-Optimizations - Essentially uses frequency analysis to determine if the virtual method call is still going to call the same method as it would previously. Regardless, we can not perform such optimizations, so whether or not it applies to C#, it does apply to D.

> History also showed us that C# introduced way to revirtualize method, for several purposes like mock. We can't simple take this argument and don't look at it with the light of history.

It doesn't revirtualize anything. C# has a profiler API that mocking frameworks can use to replace methods with their own implementations (ie: Microsoft's Moles Framework). Simply making a method virtual is not sufficient as static methods could then not be mocked. Besides that, making your classes / methods virtual for the sole purpose of mocking seems like a bad idea to me. Even if virtual was the default though, you still have to worry about final methods. Java for example uses frameworks such as Mockito to allow you to mock final methods (and static methods as well); the virtual by default doesn't change that.