opDispatch doesn't play nice with inheritance

Jonathan M Davis newsgroup.d at jmdavisprog.com
Mon Nov 19 00:55:16 UTC 2018


On Saturday, November 17, 2018 11:09:51 PM MST Carl Sturtivant via 
Digitalmars-d-learn wrote:
> On Thursday, 15 November 2018 at 19:01:45 UTC, Ali Çehreli wrote:
> > On 11/15/2018 09:14 AM, Carl Sturtivant wrote:
> > > opDispatch is special in that it allows for functions to be
> >
> > added to a
> >
> > > class or struct when undefined overtly but used elsewhere but
> >
> > it seems
> >
> > > those functions sadly are final.
> > >
> > > Can anything useful be done to remedy the situation?
> >
> > For the compiler to be able to make all opDispatch
> > instantiations virtual, it would have to first see all calls
> > that generate opDispatch instantiations. (Impossible in the
> > presence of separate compilation.)
> >
> > Only then the compiler would know how large the vtbl of the
> > base class should be and what member functions of the derived
> > class are overrides of those virtual functions.
>
> I suppose it's such administrative difficulties that led to D
> defining anything that might conceivably be overridden to be
> virtual, whether or not actually overridden.

The issue with templated functions is that you don't have the full list of
instantiations when the base class is compiled, whereas as I understand it,
the issue with virtual-by-default is more of an issue of choosing code
correctness by default over efficiency by default.

You can get some fun, subtle bugs in C++ when you call non-virtual functions
in circumstances where they were overridden and used as if they were
virtual. So, by making all public and protected class member functions
virtual by default and not allowing non-virtual functions to be overridden,
it prevents a whole class of bugs. It _does_ have some performance downsides
in that it easily leads to functions being virtual when they don't need to
be, which can be gotten around with some extra effort, but it's effectively
favoring correctness by default over efficiency. And for a lot of programs,
it's a great tradeoff, especially when the whole point of classes in D is to
use inheritance and polymorphism, and the cases where you don't need it, you
use a struct. For the rest, final can be used to devirtualize a function as
long as it's not overriding a function.

To avoid bugs in the same way that we currently do without having virtual be
the default, we probably would have had to make it illegal to override any
class functions unless they were explicitly virtual, which would have
created a different set of problems. And whether that would be better or
worse is a matter of debate. In the end, it's a matter of tradeoffs, and
which is better is likely to depend on how your applications benefit from
and use the feature. If most of your class functions are used
polymorphically, then having to mark them as virtual or having to put
virtual: at the top of your class would get really annoying, whereas if you
typically have only a few virtual functions and then lots of non-virtual
property functions (like the AAA guys apparently like to do), then having to
mark things with final to devirtualize them is very annoying. There's no
pleasing everyone. Either way, allowing overriding non-virtual functions
like C++ does would just be begging for bugs.

- Jonathan M Davis






More information about the Digitalmars-d-learn mailing list