No we should not support enum types derived from strings

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Tue May 11 21:36:46 UTC 2021


On 5/11/21 2:37 PM, Meta wrote:
> On Tuesday, 11 May 2021 at 16:44:03 UTC, Andrei Alexandrescu wrote:
>>> Again with moving the goalposts.
>>
>> To clarify: you can't make up your own definitions as you go so as to 
>> support the point you're making at the moment. You can't go "oh, call 
>> it something else than a type, my point stays". No. Your point doesn't 
>> stay.
>>
>> By the same token you can't make up your own definition of what 
>> subtyping is and isn't. Value types and reference types are 
>> well-trodden ground. You can't just claim new terminology and then 
>> prove your own point by using it.
> 
> I apologize for injecting myself into this conversation, but with all 
> due respect, what the hell are you talking about? Everything Deadalnix 
> is saying makes perfect sense - it's basic type theory, and yet you're 
> accusing him of moving goalposts and making up definitions, etc. The 
> problem is that `isSomeString` doesn't respect the LSP and the template 
> constraints on the relevant stdlib functions for enums are a hack to 
> work around that. End of story. if `isSomeString` was defined sensibly, 
> these template constraint hacks would not have to exist.
> 
> All the bluster about `popFront` on enum strings, etc. is completely 
> irrelevant, and is a red herring anyway (as was already explained).
> 
> I'm sorry for being so blunt, but this conversation is painful to read.

Being blunt is totally cool, but that doesn't make you right.

There's no true subtyping or polymorphism with value semantics. This has 
been common knowledge in C++ - inheriting a value type is an antipattern 
for many reasons, and conversion operators are to be used carefully (and 
not as a substitute to subtyping) for many other reasons.

With value types, it's all static typing, no polymorphism, no LSP beyond 
what's called ad-hoc polymorphism in the classic Caderlli et al paper 
(http://poincare.matf.bg.ac.rs/~smalkov/files/old/fp.r344.2016/public/predavanja/FP.cas.2016.07%20-%20p471-cardelli.pdf).

What can be aimed for with values is called "parametric polymorphism" 
(which is NOT subtyping) by the same paper: "Parametric polymorphism is 
obtained when a function works uniformly on a range of types; these 
types normally exhibit some common structure."

That works if and only if you can reasonably supplant the same 
primitives across said range of types. With enums that's onerous; as 
soon as you "derive" an enum from int you figure that ++x can't 
reasonably be implemented. Same goes for enum strings - you can't 
implement the expected string primitives so substitutability is out the 
window.

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.)


More information about the Digitalmars-d mailing list