transporting qualifier from parameter to the return value

Steven Schveighoffer schveiguy at yahoo.com
Sat Dec 19 20:16:32 PST 2009


On Wed, 16 Dec 2009 00:57:59 -0500, Walter Bright  
<newshound1 at digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> type constructor.  it has no meaning as a storage class since it's  
>> entirely transient (it only has any meaning inside functions).
>
> I meant does it only apply at the top level, or does it apply down  
> inside types?

I've been giving this some thought.  inout is a strange beast, and it has  
some interesting rules.  For example, let's take a struct with an already  
const member:

struct S
{
    const(char)[] str;
}

Now, we have a function that uses inout on S:

inout(char)[] getStr(inout S s)
{
    return s.str;
}

This should NOT compile, because if you pass in a mutable or immutable S,  
then the compiler casts the result back to mutable or immutable!  So inout  
is transitive only for mutable members of data types.  It's sort of  
similar to applying const to a struct with an immutable member, the const  
doesn't apply to the immutable member, only the mutable ones.

>
>> BTW, I'm unsure if U[inout(T)] should work.
>
> I just meant it as a compound type. It could as easily be:
>
>      bar!(inout(T)) foo(inout X) { ... }

It might be workable.  The only monkey wrench thrown in is that bar can do  
conditional compilation based on the constancy of T:

template bar(T)
{
   static if(is(T == const))
      alias T[] bar;
   else
      struct bar { T t1, t2; }
}

This is no good, because you don't know how to build bar when your unsure  
if T is const or not (which is the whole point of inout).  If the compiler  
can determine if bar!(T), bar!(const(T)), bar!(immutable(T)) and  
bar!(inout(T)) generate identical code (except for the constancy of T),  
then maybe it can forcibly cast the result once the return happens.  This  
might be the only time where inout can be applied to member variables  
because it's a temporary situation inside an inout function.

It's a complex situation, one that probably requires a lot of thinking.   
My recommendation at this time is to only allow bar!(inout(T)) if it is an  
alias to something that normally would be returnable/passable to an inout  
function e.g.:

template bar(T)
{
   alias T[] bar;
}

as for AA's, it might be a case where we should allow it, since we know  
AA's have the same implementation regardless of type info.

-Steve



More information about the Digitalmars-d mailing list