On 6/13/17 7:51 PM, ag0aep6g wrote:
On 06/14/2017 12:45 AM, Steven Schveighoffer wrote:
No, the fact that immutable implicitly casts to const(inout) is a
special property enabled by the knowledge that immutable data can
NEVER change, so it's OK to assume it's (at least) const for all
references. The same cannot be true of const or mutable.
In other words: Immutable can't ever become mutable, at most it can
become const.
In the same vein: Mutable can't ever become immutable, at most it can
become const.
I don't see the fundamental difference. Mutable and immutable act very
much alike. They're just on opposing ends of the scale.
The fundamental difference is that const and immutable share a
characteristic that mutable doesn't -- you can't mutate the data.
The reason const(inout) works is because const(immutable) evaluates to
just immutable.
const(<mutable>) just evaluates to const. In this way, mutable is less
"special" than immutable.
This cannot work, because g() has no idea what the true mutability of
x is. inout is not a template. This is why you can't implicitly cast
inout to anything except const, and you can't implicitly cast anything
to inout.
I don't follow. `inout const` doesn't need a template to do its thing.
Right, it's because the point at which the inout is "unwrapped" (i.e. at
the point of return), it either becomes const or immutable. Inout
functions can compile oblivious to how they will be called because the
caller can completely determine the type that should be returned. It was
the impetus to create inout in the first place -- why generate all these
functions that do the same thing, just to change the return type, let
the caller figure it out.
I'm not sure what you mean about implicit conversions. Obviously, an
inout result matches the corresponding inout argument(s). Doesn't matter
if that's an implicit conversion or whatever.
There is actually a difference. inout wraps one and exactly one type
modifier. The table in that function shows what the modifier is
depending on your collection of mutability parameters.
If ALL of them are the same, it becomes that same thing.
If any are different, you use the table to figure out. Most differences
become const, some special cases become const(inout). This special case
is solely to allow a function that takes both immutable and inout to
potentially return immutable instead of just const.
Now, this code could be made to work:
----
bool condition;
auto f(inout int* x)
{
int* y; /* mutable now */
return condition ? x : y;
}
void main()
{
int* r1 = f(new int);
const r1 = f(new immutable int);
}
----
Mutable in, mutable out. Const in, const out. Immutable in, const out.
You can't get immutable out, because y is mutable, and it cannot become
immutable. Same principle as above. You never go from mutable to
immutable or the other way around, so everything's fine, no?
The soundness of the function above seems good, but I don't know how to
reason about the return type of f. Because mutable has no type modifier,
it's hard to imagine doing this without one. And any time I think about
how to define it, it breaks down. I can't imagine const(blah(T))
evaluating to mutable, no matter what blah is called, or how it works.
Literally the ONLY place this would be useful is for inout functions,
and Andrei pretty much has declared that inout should be completely
stricken from Phobos/druntime in favor of templates. I can't imagine any
leeway for another type modifier.
const(inout) literally was an afterthought observation that we could
relax the rules for this one case and get a little more usability.
-Steve