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

Reply via email to