No we should not support enum types derived from strings

deadalnix deadalnix at gmail.com
Wed May 12 01:46:25 UTC 2021


On Tuesday, 11 May 2021 at 21:36:46 UTC, Andrei Alexandrescu 
wrote:
> Values are monomorphic. Years ago I found a bug in a large C++ 
> system that went like this:
>
> class Widget : BaseWidget {
>     ...
>     Widget* clone() {
>         assert(typeid(this) == typeid(Widget*));
>         return new Widget(*this);
>     }
> };
>
> The assert was a _monomorphism test_, i.e. it made sure that 
> the current object is actually a Widget and not something 
> derived from it, who forgot to override clone() once again.
>
> The problem was the code was doing exactly what it shouldn't 
> have, yet the assert was puzzlingly passing. Since everyone 
> here is great at teaching basic type theory, it's an obvious 
> problem - the fix is:
>
>         assert(typeid(*this) == typeid(Widget));
>
> Then the assertion started failing as expected. Following that, 
> I've used that example for years in teaching and to invariably 
> there are eyes going wide when they hear that C++ pointers are 
> monomorphic, it's the pointed-to values that are polymorphic, 
> and that's an essential distinction. (In D, just like in Java, 
> classes take care of that indirection automatically, which can 
> get some confused.)

While this is indeed very interesting, this is missing the larger 
point.

This whole model in C++ is unsound. It's easy to show. In you 
above example, the this pointer, typed as Widget*, points to an 
instance of a subclass of Widget. If you were to assign a Widget 
to that pointer (which you can do, this is a pointer to a mutable 
widget), then any references to that widget using a subtype of 
Widget is now invalid.

There is no such thing as a monomorphic pointer to a polymorphic 
type in any sound type system. That cannot be made to work. It is 
unsound. This is why in Java or C#, the type represent both the 
pointer and the pointed data, as a package, being half a value, 
half a reference type in the process. This is unavoidable, you 
can't unbundle it or everything breaks down.

So why is there an indirection in there? Simply because you 
cannot know the layout of the object at compile time when you are 
doing runtime polymorphism. But even then, you could decide to 
make it behave as a value type with eager deep copy or copy on 
write and that would work too, and it would still be polymorphic.

D is correct to use Java and C# 's model. C++'s is unsound.

But we get back to square one: this has nothing to do with the 
indirection. In fact, in the Java/C# model, class types are value 
type, which hold a reference to a payload. And the whole typing 
and subtyping business happen on these value types.


More information about the Digitalmars-d mailing list