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

Reply via email to