On Thursday, 16 March 2017 at 17:20:45 UTC, H. S. Teoh wrote:
I'm not convinced casting static array to immutable is OK. Check this out:


You aren't casting static array to immutable there, it is being implicitly sliced AND cased to immutable.

What I mean is:

char[32] s;
immutable(char)[32] i = s; // that is sane, it copies anyway
immutable(char[32]) i2 = s; // also sane


That's an implicit cast to immutable, but since both sides are still static arrays, it is no different than

int a = 0;
immutable b = a; // ok

Value types can be copied in and out of immutable implicitly without worry.

It is when they become a reference type that things go wrong. And, in isolation, the compiler knows this too:

immutable(char)[] i = s; // Error: cannot implicitly convert expression (s) of type char[32] to string


But when you put it behind a function like you did, two things happen:

1) it sees it is a return value by value, and thus unique... so it is safe to cast to immutable

char[32] func() {
        char[32] a;
        return a;
}

void main() {
immutable(char[32]) a = func(); // that's fine! it is copied so it is immutable
}

but 2), it is also willing to slice it:

char[] b = func(); // legal under current rules... but insane

and 3) knowing it is a slice of unique data, it allows it to be casted just like:

pure char[] foo() { return []; }

string implicit = foo(); // fine - pure slice must be unique due to purity rules, and unique mutable can become immutable


Combine all that and we get:

char[32] func() { }

1) char[] implicitlySliced = func(); // stupid, but allowed by language rules 2) immutable(char)[] implicitly immutable = impliciltlySliced; // ok, because it is unique...
3) crashing in bug city.





Of all those rules, preventing the implicit slice is the easiest fix:

string s = func(); // error, CAN implicitly cast from char[32] to immutable(char[32]) but can NOT implicitly cast from static to dynamic

Being a unique value, casting to immutable is perfectly sane.

immutable(char[32]) s = func(); // makes sense
string s2 = s; // nope, if you really meant it, write `s[]`

But the caller should be aware of when a reference is taken.

string s = func()[]; // I'd allow it, at least the user wrote `[]` meaning they realized it was stack data and presumably knows what that means about the slice's lifetime

Reply via email to