March 05, 2012
On Mon, 05 Mar 2012 11:17:41 -0500, Stewart Gordon <smjg_1998@yahoo.com> wrote:

> On 05/03/2012 13:49, Steven Schveighoffer wrote:
>> On Sat, 25 Feb 2012 09:02:47 -0500, Timon Gehr <timon.gehr@gmx.ch> wrote:
> <snip>
>>> inout means 'some qualifier but we don't know which one'. The call site on the other
>>> hand knows which qualifier it is. If the call is made to work there is no 'making it
>>> mutable', because it is mutable all the time. The inout function cannot change the data
>>> because it cannot know what the constancy is.
>>
>> What you would propose is that a delegate which takes a const/mutable/immutable implicitly
>> translates to one which takes an inout. I agree it can be made to work, but it does not
>> fit into the current definition of inout.
>
> I'm not sure if you understand correctly.  Is isn't a matter of implicit conversion of delegates from one type to another, but a matter of (in this case) opApply accepting a delegate with a parameter whose constancy matches that of this.

I understand the problem and the proposed solution quite well.

>> It would be ideal for inout to solve this, but it's not chartered in such a way to do so.
>
> If I'm not mistaken, inout isn't chartered to do anything particular when it occurs in a function signature nested within another.  The spec just leaves it ambiguous.

No, inout is not modifiable during the function execution.  Given the transitivity of const and immutable, inout itself must also be transitive.

Think about it this way:

inout(int)* foo(inout(int)* x)
{
   // begin here, at this point x is not modifiable
   // *x = 5; // not allowed!
   return x;
   // end here, at this point inout reverts back to it's original constancy (including return value).
}

The original definition I used for inout was "scoped const", meaning it's const within the scope and reverts back after the scope.  I did not plan for having the constancy "temporarily" revert back to the original constancy.  What you wish for is this to take a delegate which matches the constancy of the x parameter:

inout(int)* foo(inout(int) *x, void delegate(inout(int)* p) dg)
{
   dg(x); // valid, since the type matches
   return x; // oops, now x could have changed!  Even through it's an inout reference!
}

>
>> It's currently transitive, and this would break transitivity. If we want to look at
>> fundamentally redefining inout so that it can break transitivity, then we can look at
>> that. But I don't think this is a simple "add-on" to the current functionality.
> <snip>
>
> Can you give an example of how it breaks transitivity?

Using the above foo function:

void main()
{
   void bar(int *x) {*x = 5;}
   int i = 2;
   foo(&i, &bar); // this sets i to 5 via the inout reference we pass into it.
}

In other words, inout is transitively not constant during the function call.

I'm not saying we cannot bend the rules to allow for this, because clearly it doesn't violate the "true" constancy type of the data passed in, but I don't think it's a straightforward change conceptually.  I'm not a compiler writer, so I don't know how this works in their minds, I'd like to have their input.

-Steve
March 05, 2012
On 03/05/2012 11:31 PM, Steven Schveighoffer wrote:
> On Mon, 05 Mar 2012 11:17:41 -0500, Stewart Gordon <smjg_1998@yahoo.com>
> wrote:
>
>> On 05/03/2012 13:49, Steven Schveighoffer wrote:
>>> On Sat, 25 Feb 2012 09:02:47 -0500, Timon Gehr <timon.gehr@gmx.ch>
>>> wrote:
>> <snip>
>>>> inout means 'some qualifier but we don't know which one'. The call
>>>> site on the other
>>>> hand knows which qualifier it is. If the call is made to work there
>>>> is no 'making it
>>>> mutable', because it is mutable all the time. The inout function
>>>> cannot change the data
>>>> because it cannot know what the constancy is.
>>>
>>> What you would propose is that a delegate which takes a
>>> const/mutable/immutable implicitly
>>> translates to one which takes an inout. I agree it can be made to
>>> work, but it does not
>>> fit into the current definition of inout.
>>
>> I'm not sure if you understand correctly. Is isn't a matter of
>> implicit conversion of delegates from one type to another, but a
>> matter of (in this case) opApply accepting a delegate with a parameter
>> whose constancy matches that of this.
>
> I understand the problem and the proposed solution quite well.
>
>>> It would be ideal for inout to solve this, but it's not chartered in
>>> such a way to do so.
>>
>> If I'm not mistaken, inout isn't chartered to do anything particular
>> when it occurs in a function signature nested within another. The spec
>> just leaves it ambiguous.
>
> No, inout is not modifiable during the function execution. Given the
> transitivity of const and immutable, inout itself must also be transitive.
>
> Think about it this way:
>
> inout(int)* foo(inout(int)* x)
> {
> // begin here, at this point x is not modifiable
> // *x = 5; // not allowed!
> return x;
> // end here, at this point inout reverts back to it's original constancy
> (including return value).
> }

I don't think this is the best way to think about inout. Try to think about it as if the constancy was determined, but unknown. It does not actually change, the function just does not know what it is because it has to work in a polymorphic way.

>
> The original definition I used for inout was "scoped const", meaning
> it's const within the scope and reverts back after the scope. I did not
> plan for having the constancy "temporarily" revert back to the original
> constancy. What you wish for is this to take a delegate which matches
> the constancy of the x parameter:
>
> inout(int)* foo(inout(int) *x, void delegate(inout(int)* p) dg)
> {
> dg(x); // valid, since the type matches
> return x; // oops, now x could have changed! Even through it's an inout
> reference!
> }
>

Well, that can happen even for const references. What is your point?


>>
>>> It's currently transitive, and this would break transitivity. If we
>>> want to look at
>>> fundamentally redefining inout so that it can break transitivity,
>>> then we can look at
>>> that. But I don't think this is a simple "add-on" to the current
>>> functionality.
>> <snip>
>>
>> Can you give an example of how it breaks transitivity?
>
> Using the above foo function:
>
> void main()
> {
> void bar(int *x) {*x = 5;}
> int i = 2;
> foo(&i, &bar); // this sets i to 5 via the inout reference we pass into it.
> }
>
> In other words, inout is transitively not constant during the function
> call.
>

Because it has been matched as *mutable*. There is no issue.

> I'm not saying we cannot bend the rules to allow for this, because
> clearly it doesn't violate the "true" constancy type of the data passed
> in, but I don't think it's a straightforward change conceptually. I'm
> not a compiler writer, so I don't know how this works in their minds,
> I'd like to have their input.

Implementation of what you propose should be quite simple. The issue is with the design, i.e. allowing both tying the inout in the delegate parameter signature to the inout in the enclosing signature and having an independent inout delegate parameter needs workable syntax.

March 05, 2012
On Mon, 05 Mar 2012 18:01:34 -0500, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 03/05/2012 11:31 PM, Steven Schveighoffer wrote:
>> On Mon, 05 Mar 2012 11:17:41 -0500, Stewart Gordon <smjg_1998@yahoo.com>
>> wrote:
>>
>>> On 05/03/2012 13:49, Steven Schveighoffer wrote:
>>>> On Sat, 25 Feb 2012 09:02:47 -0500, Timon Gehr <timon.gehr@gmx.ch>
>>>> wrote:
>>> <snip>
>>>>> inout means 'some qualifier but we don't know which one'. The call
>>>>> site on the other
>>>>> hand knows which qualifier it is. If the call is made to work there
>>>>> is no 'making it
>>>>> mutable', because it is mutable all the time. The inout function
>>>>> cannot change the data
>>>>> because it cannot know what the constancy is.
>>>>
>>>> What you would propose is that a delegate which takes a
>>>> const/mutable/immutable implicitly
>>>> translates to one which takes an inout. I agree it can be made to
>>>> work, but it does not
>>>> fit into the current definition of inout.
>>>
>>> I'm not sure if you understand correctly. Is isn't a matter of
>>> implicit conversion of delegates from one type to another, but a
>>> matter of (in this case) opApply accepting a delegate with a parameter
>>> whose constancy matches that of this.
>>
>> I understand the problem and the proposed solution quite well.
>>
>>>> It would be ideal for inout to solve this, but it's not chartered in
>>>> such a way to do so.
>>>
>>> If I'm not mistaken, inout isn't chartered to do anything particular
>>> when it occurs in a function signature nested within another. The spec
>>> just leaves it ambiguous.
>>
>> No, inout is not modifiable during the function execution. Given the
>> transitivity of const and immutable, inout itself must also be transitive.
>>
>> Think about it this way:
>>
>> inout(int)* foo(inout(int)* x)
>> {
>> // begin here, at this point x is not modifiable
>> // *x = 5; // not allowed!
>> return x;
>> // end here, at this point inout reverts back to it's original constancy
>> (including return value).
>> }
>
> I don't think this is the best way to think about inout. Try to think about it as if the constancy was determined, but unknown. It does not actually change, the function just does not know what it is because it has to work in a polymorphic way.

Best way or not, it was designed and accepted using these assumptions.  Again, I am not against the idea, I just want to hear what Walter and company think about it.

>
>>
>> The original definition I used for inout was "scoped const", meaning
>> it's const within the scope and reverts back after the scope. I did not
>> plan for having the constancy "temporarily" revert back to the original
>> constancy. What you wish for is this to take a delegate which matches
>> the constancy of the x parameter:
>>
>> inout(int)* foo(inout(int) *x, void delegate(inout(int)* p) dg)
>> {
>> dg(x); // valid, since the type matches
>> return x; // oops, now x could have changed! Even through it's an inout
>> reference!
>> }
>>
>
> Well, that can happen even for const references. What is your point?

Not via the const parameter.  For example, mark the delegate and the function as pure, it cannot happen with const.

>>>> It's currently transitive, and this would break transitivity. If we
>>>> want to look at
>>>> fundamentally redefining inout so that it can break transitivity,
>>>> then we can look at
>>>> that. But I don't think this is a simple "add-on" to the current
>>>> functionality.
>>> <snip>
>>>
>>> Can you give an example of how it breaks transitivity?
>>
>> Using the above foo function:
>>
>> void main()
>> {
>> void bar(int *x) {*x = 5;}
>> int i = 2;
>> foo(&i, &bar); // this sets i to 5 via the inout reference we pass into it.
>> }
>>
>> In other words, inout is transitively not constant during the function
>> call.
>>
>
> Because it has been matched as *mutable*. There is no issue.

There are two parts to inout, one is that it can be one function called 3 different ways, the other is that you know it's constant during function execution.  Some people like that second part, even if it doesn't fully guarantee everything.  I.e. there's a reason people use const in C++ besides it being trendy.

>
>> I'm not saying we cannot bend the rules to allow for this, because
>> clearly it doesn't violate the "true" constancy type of the data passed
>> in, but I don't think it's a straightforward change conceptually. I'm
>> not a compiler writer, so I don't know how this works in their minds,
>> I'd like to have their input.
>
> Implementation of what you propose should be quite simple. The issue is with the design, i.e. allowing both tying the inout in the delegate parameter signature to the inout in the enclosing signature and having an independent inout delegate parameter needs workable syntax.

I think it can be done:

1. determine inout match based on existing rules, excluding delegate parameters.
2. change delegate parameter inouts to matched value.
3. Use implicit delegate conversion (using contravariance) to allow passing delegates of proper type.

For example:

void foo(inout(int)* x, void delegate(inout(int)* y) dg);

void main()
{
   int mx;
   immutable int ix;
   const int cx;

   void bar1(int *mp) {}
   void bar2(immutable(int) *ip) {}
   void bar3(const(int) *cp) {}
   void bar4(inout(int) *iop) {}

   // inout matched as mutable due to mx, signature becomes void foo(int *x, void delegate(int *y) dg);
   foo(&mx, &bar1); // fine, direct match of both parameters
   foo(&mx, &bar2); // not fine, immutable delegate does not implicitly convert to mutable
   foo(&mx, &bar3); // fine, const delegate can implicitly convert to mutable
   foo(&mx, &bar4); // fine, inout delegate can implicitly convert to mutable

   // signature becomes void foo(immutable(int) *x, void delegate(immutable(int) *y) dg);
   foo(&ix, &bar1); // error
   foo(&ix, &bar2); // ok
   foo(&ix, &bar3); // fine, const delegate can implicitly convert to immutable
   foo(&ix, &bar4); // fine, inout delegate can implicitly convert to immutable

   // signature becomes void foo(const(int) *x, void delegate(const(int) *y) dg);
   foo(&cx, &bar1); // error
   foo(&cx, &bar2); // error
   foo(&cx, &bar3); // ok
   foo(&cx, &bar4); // ok

   // etc...
}

Note that Walter has explicitly rejected contravariance conversion for delegates.  You have good persuasive skills, maybe you can help :)  See bug http://d.puremagic.com/issues/show_bug.cgi?id=3180 and http://d.puremagic.com/issues/show_bug.cgi?id=3075

-Steve
March 06, 2012
On 05/03/2012 22:31, Steven Schveighoffer wrote:
> On Mon, 05 Mar 2012 11:17:41 -0500, Stewart Gordon <smjg_1998@yahoo.com> wrote:
>
>> On 05/03/2012 13:49, Steven Schveighoffer wrote:
<snip>
>>> It's currently transitive, and this would break transitivity. If we want to look at
>>> fundamentally redefining inout so that it can break transitivity, then we can look at
>>> that. But I don't think this is a simple "add-on" to the current functionality.
>> <snip>
>>
>> Can you give an example of how it breaks transitivity?
>
> Using the above foo function:

Which has only one level of indirection.  So I can't see how transitivity comes into play.

> void main()
> {
> void bar(int *x) {*x = 5;}
> int i = 2;
> foo(&i, &bar); // this sets i to 5 via the inout reference we pass into it.
> }
<snip>

The foo function doesn't set i.  The bar function does.

The design of inout is that the function with inout parameters doesn't know or care about the constancy of its arguments, _therefore_ cannot modify the data.  The function that is passed in as a delegate, OTOH, _does_ know the constancy of its argument, and so _can_ modify it if the constancy permits.  This is necessary to support foreach in the way we're talking about.

Stewart.
March 06, 2012
On Mon, 05 Mar 2012 20:34:09 -0500, Stewart Gordon <smjg_1998@yahoo.com> wrote:

> On 05/03/2012 22:31, Steven Schveighoffer wrote:
>> On Mon, 05 Mar 2012 11:17:41 -0500, Stewart Gordon <smjg_1998@yahoo.com> wrote:
>>
>>> On 05/03/2012 13:49, Steven Schveighoffer wrote:
> <snip>
>>>> It's currently transitive, and this would break transitivity. If we want to look at
>>>> fundamentally redefining inout so that it can break transitivity, then we can look at
>>>> that. But I don't think this is a simple "add-on" to the current functionality.
>>> <snip>
>>>
>>> Can you give an example of how it breaks transitivity?
>>
>> Using the above foo function:
>
> Which has only one level of indirection.  So I can't see how transitivity comes into play.
>
>> void main()
>> {
>> void bar(int *x) {*x = 5;}
>> int i = 2;
>> foo(&i, &bar); // this sets i to 5 via the inout reference we pass into it.
>> }
> <snip>
>
> The foo function doesn't set i.  The bar function does.

The issue is that the bar function modifies i via the inout parameter to foo.  That is, bar does not modify i directly, but modifies foo's parameter.

>
> The design of inout is that the function with inout parameters doesn't know or care about the constancy of its arguments, _therefore_ cannot modify the data.  The function that is passed in as a delegate, OTOH, _does_ know the constancy of its argument, and so _can_ modify it if the constancy permits.  This is necessary to support foreach in the way we're talking about.

I think maybe transitivity is not the right term.  It's just a straight const violation.

The thing I'm getting at is, there are two pieces to inout -- one is, it passes the constancy of the parameters back through the return value.  The second is it acts as a surrogate for const in terms of API guarantees.  That means, if I pass in a parameter as an inout parameter, it will not be modified during the function execution *through that parameter*.

Again, I want to stress that I think the idea is sound and could be implemented.  But I think it fundamentally changes the way inout is conceptually designed.

-Steve
March 06, 2012
On 03/06/2012 12:27 AM, Steven Schveighoffer wrote:
...
>
> There are two parts to inout, one is that it can be one function called
> 3 different ways, the other is that you know it's constant during
> function execution. Some people like that second part, even if it
> doesn't fully guarantee everything. I.e. there's a reason people use
> const in C++ besides it being trendy.
>

By passing a delegate that changes an inout-matched argument it is made explicit that inout data may change. Technically, none of the existing guarantees are lost, we just add some expressiveness to the type system.


>>
>>> I'm not saying we cannot bend the rules to allow for this, because
>>> clearly it doesn't violate the "true" constancy type of the data passed
>>> in, but I don't think it's a straightforward change conceptually. I'm
>>> not a compiler writer, so I don't know how this works in their minds,
>>> I'd like to have their input.
>>
>> Implementation of what you propose should be quite simple. The issue
>> is with the design, i.e. allowing both tying the inout in the delegate
>> parameter signature to the inout in the enclosing signature and having
>> an independent inout delegate parameter needs workable syntax.
>
> I think it can be done:
>
> 1. determine inout match based on existing rules, excluding delegate
> parameters.
> 2. change delegate parameter inouts to matched value.
> 3. Use implicit delegate conversion (using contravariance) to allow
> passing delegates of proper type.
>
> For example:
>
> void foo(inout(int)* x, void delegate(inout(int)* y) dg);
>
> void main()
> {
> int mx;
> immutable int ix;
> const int cx;
>
> void bar1(int *mp) {}
> void bar2(immutable(int) *ip) {}
> void bar3(const(int) *cp) {}
> void bar4(inout(int) *iop) {}
>
> // inout matched as mutable due to mx, signature becomes void foo(int
> *x, void delegate(int *y) dg);
> foo(&mx, &bar1); // fine, direct match of both parameters
> foo(&mx, &bar2); // not fine, immutable delegate does not implicitly
> convert to mutable
> foo(&mx, &bar3); // fine, const delegate can implicitly convert to mutable
> foo(&mx, &bar4); // fine, inout delegate can implicitly convert to mutable
>
> // signature becomes void foo(immutable(int) *x, void
> delegate(immutable(int) *y) dg);
> foo(&ix, &bar1); // error
> foo(&ix, &bar2); // ok
> foo(&ix, &bar3); // fine, const delegate can implicitly convert to
> immutable
> foo(&ix, &bar4); // fine, inout delegate can implicitly convert to
> immutable
>
> // signature becomes void foo(const(int) *x, void delegate(const(int)
> *y) dg);
> foo(&cx, &bar1); // error
> foo(&cx, &bar2); // error
> foo(&cx, &bar3); // ok
> foo(&cx, &bar4); // ok
>
> // etc...
> }

I understand, but how would you support this use case?:

inout(int)[] foo(inout(int)[] delegate(inout(int)[] dg), inout(int)[] arr){
    int[] x = dg(new int[16]);
    immutable(int)[] y = dg(new immutable(int)[16]);
    // ...
    inout(int)[] z = dg(arr);
    return foo(z,y,z);
}

In essence, it should be possible to pass an inout delegate to an inout function, such that the function can use the delegate as an inout delegate.


>
> Note that Walter has explicitly rejected contravariance conversion for
> delegates.

That is unfortunate.

> You have good persuasive skills, maybe you can help :) See
> bug http://d.puremagic.com/issues/show_bug.cgi?id=3180 and
> http://d.puremagic.com/issues/show_bug.cgi?id=3075
>

IIRC Kenji Hara has already started attempts to loosen the restrictions regarding delegate implicit conversions. Hopefully Walter will reconsider.







March 07, 2012
On Tue, 06 Mar 2012 05:11:34 -0500, Timon Gehr <timon.gehr@gmx.ch> wrote:

> On 03/06/2012 12:27 AM, Steven Schveighoffer wrote:
> ...
>>
>> There are two parts to inout, one is that it can be one function called
>> 3 different ways, the other is that you know it's constant during
>> function execution. Some people like that second part, even if it
>> doesn't fully guarantee everything. I.e. there's a reason people use
>> const in C++ besides it being trendy.
>>
>
> By passing a delegate that changes an inout-matched argument it is made explicit that inout data may change. Technically, none of the existing guarantees are lost, we just add some expressiveness to the type system.

Yes, I understand that it works.  I know that it doesn't violate technically any const guarantees.

In fact, I think this is valid D code:

int i;
const int *pi = &i;
int *p = cast()pi;
*p = 5; // legal because I know this points at i, and i is really mutable

But from an API point of view, I look at at inout as guaranteeing anything the parameter points at won't change while inside the function *using that parameter*.  Even though it's legal, it's disingenuous (at least as long as we define inout that way).

An interesting side note is that inout (if designed in this way) can allow the above code snippit to be modularized.

>
>
>>>
>>>> I'm not saying we cannot bend the rules to allow for this, because
>>>> clearly it doesn't violate the "true" constancy type of the data passed
>>>> in, but I don't think it's a straightforward change conceptually. I'm
>>>> not a compiler writer, so I don't know how this works in their minds,
>>>> I'd like to have their input.
>>>
>>> Implementation of what you propose should be quite simple. The issue
>>> is with the design, i.e. allowing both tying the inout in the delegate
>>> parameter signature to the inout in the enclosing signature and having
>>> an independent inout delegate parameter needs workable syntax.
>>
>> I think it can be done:
>>
>> 1. determine inout match based on existing rules, excluding delegate
>> parameters.
>> 2. change delegate parameter inouts to matched value.
>> 3. Use implicit delegate conversion (using contravariance) to allow
>> passing delegates of proper type.
>>
>> For example:
>>
>> void foo(inout(int)* x, void delegate(inout(int)* y) dg);
>>
>> void main()
>> {
>> int mx;
>> immutable int ix;
>> const int cx;
>>
>> void bar1(int *mp) {}
>> void bar2(immutable(int) *ip) {}
>> void bar3(const(int) *cp) {}
>> void bar4(inout(int) *iop) {}
>>
>> // inout matched as mutable due to mx, signature becomes void foo(int
>> *x, void delegate(int *y) dg);
>> foo(&mx, &bar1); // fine, direct match of both parameters
>> foo(&mx, &bar2); // not fine, immutable delegate does not implicitly
>> convert to mutable
>> foo(&mx, &bar3); // fine, const delegate can implicitly convert to mutable
>> foo(&mx, &bar4); // fine, inout delegate can implicitly convert to mutable
>>
>> // signature becomes void foo(immutable(int) *x, void
>> delegate(immutable(int) *y) dg);
>> foo(&ix, &bar1); // error
>> foo(&ix, &bar2); // ok
>> foo(&ix, &bar3); // fine, const delegate can implicitly convert to
>> immutable
>> foo(&ix, &bar4); // fine, inout delegate can implicitly convert to
>> immutable
>>
>> // signature becomes void foo(const(int) *x, void delegate(const(int)
>> *y) dg);
>> foo(&cx, &bar1); // error
>> foo(&cx, &bar2); // error
>> foo(&cx, &bar3); // ok
>> foo(&cx, &bar4); // ok
>>
>> // etc...
>> }
>
> I understand, but how would you support this use case?:
>
> inout(int)[] foo(inout(int)[] delegate(inout(int)[] dg), inout(int)[] arr){
>      int[] x = dg(new int[16]);
>      immutable(int)[] y = dg(new immutable(int)[16]);
>      // ...
>      inout(int)[] z = dg(arr);
>      return foo(z,y,z);
> }

As usual, you find and poke holes in all my arguments :)  I'm thinking that in order to make this work we need a way to specify an inout modifier really represents the matched type rather than a full-fledged inout parameter.

This is not a good thing -- inout is already pretty weird and hard to understand.

Need to do some more thinking, maybe there's an easy way.

>> Note that Walter has explicitly rejected contravariance conversion for
>> delegates.
>
> That is unfortunate.
>
>> You have good persuasive skills, maybe you can help :) See
>> bug http://d.puremagic.com/issues/show_bug.cgi?id=3180 and
>> http://d.puremagic.com/issues/show_bug.cgi?id=3075
>>
>
> IIRC Kenji Hara has already started attempts to loosen the restrictions regarding delegate implicit conversions. Hopefully Walter will reconsider.

I hope so.  This is a vastly awesome untapped low-hanging fruit.

-Steve
March 07, 2012
On 07/03/2012 15:41, Steven Schveighoffer wrote:
<snip>
> In fact, I think this is valid D code:
>
> int i;
> const int *pi = &i;
> int *p = cast()pi;
> *p = 5; // legal because I know this points at i, and i is really mutable

cast() is an abomination.  I'm not sure OTTOMH whether it's a bug that it works.

> But from an API point of view, I look at at inout as guaranteeing anything the parameter
> points at won't change while inside the function *using that parameter*. Even though it's
> legal, it's disingenuous (at least as long as we define inout that way).

That's what const is for.

The whole point of inout is that the caller has the choice of whether to pass in and get out again mutable, const or immutable data.  Allowing the caller to pass in a delegate with a mutable, const or immutable parameter would fit right in with this.

<snip>
> As usual, you find and poke holes in all my arguments :) I'm thinking that in order to
> make this work we need a way to specify an inout modifier really represents the matched
> type rather than a full-fledged inout parameter.
<snip>

Yes, and ways of specifying this have been suggested early in this thread.

Stewart.
March 07, 2012
On Wed, 07 Mar 2012 17:37:53 -0500, Stewart Gordon <smjg_1998@yahoo.com> wrote:

> On 07/03/2012 15:41, Steven Schveighoffer wrote:
> <snip>
>> In fact, I think this is valid D code:
>>
>> int i;
>> const int *pi = &i;
>> int *p = cast()pi;
>> *p = 5; // legal because I know this points at i, and i is really mutable
>
> cast() is an abomination.  I'm not sure OTTOMH whether it's a bug that it works.

Sorry, it's just easier than typing cast(int*).

And I believe it's legal, as long as you *know* that the underlying data is mutable.  The above code snippit is legal, because it is shown as long as the first two lines are included that the actual data is mutable.

>> But from an API point of view, I look at at inout as guaranteeing anything the parameter
>> points at won't change while inside the function *using that parameter*. Even though it's
>> legal, it's disingenuous (at least as long as we define inout that way).
>
> That's what const is for.

And inout.  Sorry, it was meant that way, even if you don't agree.

-Steve
March 07, 2012
On 07/03/2012 22:48, Steven Schveighoffer wrote:
> On Wed, 07 Mar 2012 17:37:53 -0500, Stewart Gordon <smjg_1998@yahoo.com> wrote:
<snip>
>> cast() is an abomination. I'm not sure OTTOMH whether it's a bug that it works.
>
> Sorry, it's just easier than typing cast(int*).

Which is another abomination.  The means of casting away constancy should be explicit.

<snip>
>>> But from an API point of view, I look at at inout as guaranteeing anything the parameter
>>> points at won't change while inside the function *using that parameter*. Even though it's
>>> legal, it's disingenuous (at least as long as we define inout that way).
>>
>> That's what const is for.
>
> And inout. Sorry, it was meant that way, even if you don't agree.

Maybe _you_ meant it that way, but did anyone else?

Stewart.