On 4/15/16 3:28 PM, Andrei Alexandrescu wrote:
On 4/15/16 2:39 PM, Steven Schveighoffer wrote:
On 4/15/16 1:11 PM, Andrei Alexandrescu wrote:

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.

In fact, a mutable slice must be passed (slice is not marked as inout).


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.

You can add more flexibility and keep inout at the same time. The nice feature here is that inout protects the elements of s that aren't in slice, and there is no requirement to verify s and slice are the same underlying type, etc.

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.

Nope. Actually inout has proven to have a more interesting property of not requiring casting.


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

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

(point stays)

Yes, thanks, that is what I meant.


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.

No, because it's not sound. you cannot cast to const through 2+ indirections. However inout works there.

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.

I assure you, these limitations were self-imposed. I insisted on them, without realizing that they would cause problems with generic code. I thought they would be good "lint" detection.

https://issues.dlang.org/show_bug.cgi?id=3748

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.

It must be a type qualifier or it doesn't 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.

I don't know what this argument is saying?

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.

Absolutely similar. There are ways around it, but at the end of the day, the compiler is complaining that the line can never be reached, when in fact it can (just pass a short in). Just like there are ways around the inout local variable requirement.

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.

I didn't see it?

-Steve

Reply via email to