Comment #0 by qs.il.paperinik — 2019-01-26T00:52:01Z
Connecting two pointers/slices of class handles results in weird error messages and behavior.
@safe:
// disables constant folding!
bool condValue;
bool cond() { return condValue; };
class Base { }
class Derived : Base { }
Base base;
Derived derived;
static this()
{
base = new Base;
derived = new Derived;
condValue = false;
}
Base[] baseArr;
Derived[] derivedArr;
In this setup, the expression
auto arr = cond() ? baseArr : derivedArr;
gives the error message
Error: incompatible types for (baseArr) : (derivedArr): Base[] and Derived[]
while clearly const(Base)[] is the best common type. If this is not liked, void*[] is another option.
Explicitly casting `derivedArr` to `const(Base)[]` solves that.
It hinders type inference and usage of `auto`, but fortunately, it won't do actual harm.
Creating pointers is no issue.
Base* basePtr = &base;
Derived* derivedPtr = &derived;
Connecting them in a tenery expression gives an undescriptive error message:
Error: cannot implicitly convert expression [..] of type Base* to Base*
This is useless while the type should be const(Base)*.
Surprisingly, this statement compiles:
*(cond() ? basePtr : derivedPtr) = new Base();
Note that cond() returns false, i.e. derivedPtr now points to a Base object.
Note that this is @safe code.
Comment #1 by qs.il.paperinik — 2019-06-06T21:18:23Z
The same is true for interfaces:
interface I { }
interface A : I { }
bool condValue;
bool cond() { return condValue; }
pragma(msg, typeof(cond() ? &a : cond() ? &b : &i)); // I*
I* iPtr = cond() ? &a : &i; // fails with error message: cannot assign I* to I*
const(I)* iPtr = cond() ? &a : &i; // succeeds
(cond() ? a : i) = i; // succeeds and breaks @safe
Comment #2 by robert.schadek — 2024-12-13T19:02:12Z