So what does (inout int = 0) do?

Andrei Alexandrescu via Digitalmars-d digitalmars-d at puremagic.com
Fri Apr 15 12:28:02 PDT 2016


On 4/15/16 2:39 PM, Steven Schveighoffer wrote:
> 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.

A better support for this argument is std.array.replaceSlice at 
https://github.com/D-Programming-Language/phobos/blob/master/std/array.d#L2594:

inout(T)[] replaceSlice(T)(inout(T)[] s, in T[] slice, in T[] replacement);

So here we are guaranteed that (a) the result type is the same as the 
first argument, and (b) the first argument is never modified even if a 
mutable slice is passed.

I agree this is a nice property, and one that C++ does not enjoy. The 
questions are of course how important it is, how useful it is, and what 
price it is worth.

Getting back to replaceSlice I'd define it in more flexible terms 
anyway. So I'd eliminate the use of inout there even if it did add value.

>>> 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.

This is correct but incomplete. The omitted part is that inout is 
valuable when $EVERYTHING_YOU_SAID and also you want to transport the 
qualifier from an argument to the result. This diminishes its importance 
considerably for all folks, including those for whom const is important.

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

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

(point stays)

> 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.

Should this work as well?

void popFront(ref const(T)[] arr);

In other words conversion of ref T[] to ref const(T)[] is sound.

>> 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.

I'm not sure - at all in fact. This is at the tail of a sequence of 
changes of inout, and there is a history of such mini-designs leading to 
complications, regressions, and further mini-designs. It's the wolf that 
eats the dog that eats the cat that eats the mouse. We fix this and 
there's another and then another and then another. It has already happened.

In fact Walter's and my design of inout is a prime example of the 
failings of that approach. We underdesigned it to work in a few small 
examples. We knew we lost when Kenji figured inout must be a type 
qualifier (we were hoping to getting away with it being a sort of a 
placeholder/wildcard). I think we should have pulled it back then. It's 
become a mini-monster that only wants more attention, more language 
changes, more work.

> 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.

This is an example of the mini-monster: the use of inout is necessary to 
satisfy the existence of inout.

> 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.

Not at all! There are very nice solutions for this, including looking at 
T or recursion. I think we can safely strike this one.

>> 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?

I thought I did. Use one-liner functions that forward to templates.


Andrei



More information about the Digitalmars-d mailing list