No we should not support enum types derived from strings

Meta jared771 at gmail.com
Wed May 12 02:36:31 UTC 2021


On Tuesday, 11 May 2021 at 21:36:46 UTC, Andrei Alexandrescu 
wrote:
>> 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).

Of course, but I thought the conversation was about strings, not 
value types. Last I checked, strings are reference types, in the 
same way that Java objects are reference types.

> What can be aimed for with values is called "parametric 
> polymorphism" (which is NOT subtyping) by the same paper:

The nice thing about D's template constraints, though, is that it 
allows us to impose subtype polymorphism on a parametrically 
polymorphic function.

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

++x still fulfills the contract that the derived enum has 
inherited from `int`: `++: int -> int`. It easily passes the 
substitutability test. Likewise, enums with a base type of string 
fulfill all the same contracts that `string` does.

Nowhere in the contract of the string type does it specify that 
`s[1..$]` returns a value of the same type as `s`, just of type 
`string`, which a string enum does.

> Values are monomorphic.

Are you saying that all values are monomorphic, or that _value 
types_ 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

Just so we're clear, my previous post was not trying to insinuate 
that I am an expert in type theory and you are just too ignorant 
to understand the arguments presented. I don't claim to be 
anything close to an expert and only know the basics, and you're 
the one with the doctorate here.

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

You just said a paragraph back that values are monomorphic. So 
are pointed-to values monomorphic or polymorphic? This isn't a 
gotcha; I'm just confused about which you meant.

I think the point you are trying to make with this story is that 
an operation on an enum that returns the base type will lead to 
confusing/wrong behaviour and allowing it for template functions 
which are meant to take strings would be bad design, just like it 
was with Widget.clone(). Is that right?


More information about the Digitalmars-d mailing list