Inout unclearness

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Mon Jul 13 06:50:01 PDT 2015


On 7/12/15 1:03 AM, Max Klimov wrote:
> inout(A) bar(inout(A) x) // compilation error
> {
>      Rebindable!(typeof(return)) r;
>      r = x;
>      return r;
> }
>
> Rebindable doesn't handle the case of inout type and I don't think that
> it can do it because it is possible to cast to inout or to keep inout
> variables only inside the proper inout function.

So a variable cannot be inout in a struct, because once it leaves the 
function, it's not clear how to cast that part of the struct to 
something else. In other words, a struct like this:

struct X(T)
{
   T t;
}

X!(int) x1;
X!(const(int)) x2 = x1;

Techincally, the assignment should be allowed, but the compiler cannot 
see into the template to see if it's actually the same, or even if the 
template parameter applies to anything in the struct. One can do 
something like:

struct X(T)
{
    static if(is(T == const))
      bool screwup;
    T t;
}

With inout, it's even more tricky, because the compiler has to ensure 
it's not inout when it leaves the function. And it's not possible in 
some cases to do this.

At the end of the day, this comes down to D not supporting tail-const 
classes. If that was supported in the language, this is all doable.

> So, I have to make some
> silly workarounds with castings in this case. The same situation happens
> in several places in phobos when arguments type is deductible. For
> example, std.array.replaceInPlace(...), std.array.join(...), etc, can
> not be used with inout(T) parameters.

Right, this is because it uses generated structs internally.

> The second question: if I want to provide inout function but it fails
> like in the example above, what is common practice? Just use casting? Or
> make a templated version and provide hand-writing code for all cases
> (mutable, const, immutable)? Or something wrong with inout qualifier?

You can simply use a template function without hand-written cases. This 
is what inout was meant to replace.

In your example:

T bar(T)(T t) if(is(Unqual!T : A))
{
    // same implementation
}

Of course, this doesn't work for inout!A as a parameter, if that is what 
you have :)

But you could specifically cast it to/from const, or do something like:

T bar(T)(T t) if(is(Unqual!T : A))
{
    static if(is(T == inout))
      return cast(T)(.bar(cast(const(Unqual!T))t));
    else
    {
        // real implementation
    }
}

-Steve


More information about the Digitalmars-d mailing list