So what does (inout int = 0) do?

Steven Schveighoffer via Digitalmars-d digitalmars-d at puremagic.com
Fri Apr 15 11:39:01 PDT 2016


On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:
> On 04/15/2016 12:19 PM, Kenji Hara via Digitalmars-d wrote:
>>
>> Didn't you use array.dup until now? It's a good example to handle
>> qualifiers with inout.
>
> Would it be difficult to make it work without inout?

T[] dup(T)(T[] arr)

this should be doable. Problem is, you get identical instantiations for 
each of the different qualifiers, unless you take different actions 
based on the mutability. Instead:

inout(T)[] dup(T)(inout(T)[] arr)

This is one instantiation, no matter the mutability of the parameter. 
And it guarantees no molestation of arr, even if it's mutable.

This would be much more difficult with a struct/class, whereas with 
inout it's pretty simple.

But I think dup as it is defined is a bad example, because as defined by 
the language, it implies that you want a mutable version where the 
source may be const/immutable. In the general sense, a duplication 
function where you get the *same* mutability is more applicable for inout.

>> It's not sensible at all, inout is already well-defined and has much
>> power in D's type system.
>> Removing it is just a foolish idea.
>
> What are a few examples of the power of inout?

One thing to understand is that inout is only valuable if you think 
const is valuable. That is, you think the advertisement of "no, I will 
not modify this parameter, give me whatever you got" is of value. If you 
don't care, then templates suffice.

void popFront(T)(inout(T)[] arr)

This is possible only with inout. const will not cut it. The current 
definition is:

void popFront(T)(T[] arr)

which is OK, but there is no advertisement that popFront doesn't change 
any data in arr.

> What things does inout afford us, that would be otherwise not achievable?

advertisement of const without having to cast the type to const (and all 
the limitations that entail).

>> If you worry the future of Phobos written in D, first you would need to
>> think about @safe.
>> It's yet not well defined/implemented by compiler, and many Phobos code
>> are marked as @trusted.
>> Does it has lower priority than complain to a small hack for the
>> *current* inout limitation?
>
> The thing about @safe is it does enable things that otherwise would not
> be possible. Overall I agree there are plenty of things that deserve a
> revisit, but just putting in competition things against one another is
> unlikely to shed light on their technical merit.

I think the point of Kenji's argument is that inout's current 
limitations are what you are bumping into, and those limitations are 
unnecessary and arbitrary. We can make inout better and more consistent. 
Pretty easily actually. We can certainly fix the inout int = 0 problem.

> To restate my arguments:
>
> 1. The motivation of inout is clear and simple - have it as a
> placeholder for any other qualifier so as to avoid the method
> duplication observed in C++. However, it has over time grown into a
> feature of which complexity way transcends its small usefulness.

It has some rough edges. These can be smoothed out.

> 2. Attempting to make inout useful have created their own problems,
> solving which in turn have increased its complexity. This cycle of
> accretions has led over time to a vortex of oddity in the middle of the
> type system.

This is not what you are railing against. The current limitations (and 
their workarounds) are self-imposed, we just need to get rid of them.

An interesting thing is that when you involve generic code, certain 
"good ideas" become very inconvenient. For example, this whole 
discussion is based on the idea that "if you don't have any inout 
parameters, why are you declaring inout variables? It makes no sense!" A 
very sensible and logical idea. But when you want code that works with 
or without inout variables, all of a sudden the same code is throwing an 
error in some cases because of an unforeseen situation.

Another example is code like this:

int firstInt(T...)(T t)
{
   foreach(ref x; t)
   {
       static if(typeof(x) == int)
          return x;
   }
   return -1;
}

This throws an error because if there is an int in T..., then return -1 
statement is "unreachable". This is similar to the inout int = 0 case. 
In non-generic code, it makes sense to flag code that won't be reached. 
But in generic code, it's actually not a true statement for all 
instantiations of the template! It's another limitation we should relax.

> 3. For all problems that inout is purported to solve, I know of idioms
> that are definitely simpler and overall almost as good if not better. So
> a hard question is whether the existence is justified.

I know of no "better" idioms, in terms of code generation and 
specificity, to replace inout (or at least, inout as I envision it 
should be). Care to elaborate?

-Steve


More information about the Digitalmars-d mailing list