[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2022-12-17 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=7355

Iain Buclaw  changed:

   What|Removed |Added

   Priority|P2  |P3

--


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-04 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #20 from timon.g...@gmx.ch 2012-02-04 10:05:05 PST ---
(In reply to comment #19)
> (In reply to comment #18)
> > (In reply to comment #17)
> > > try at a minimum immutable, mutable, and inout.  If more than one of these
> > > typechecks, the call is ambiguous.
> > 
> > What if one is a better match than the other? If it should fail I think we
> > should use the repaired overload resolution. It has exactly the required
> > semantics.
> 
> Example?  How can immutable match "better" than mutable?  I guess it would
> depend on the definition of "better".

class A{
A x()const{return new A;}
alias x this;
}

int foo(immutable(A) x){return 1;}
int foo(A x){return 2;}

static assert(foo(new immutable(A)) == 1);

The overload is resolved to the first function because it is an exact match
whereas the second overload is a match with implicit conversions. Your proposed
rules would always use the alias this when matching an inout(A) parameter, and
that is probably not what is wanted. Interestingly, the compiler currently
seems to explore the alias this of the alias this of the alias this... and
never terminates. (Also see issue 7437).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #19 from Steven Schveighoffer  2012-02-03 
17:18:54 PST ---
(In reply to comment #18)
> (In reply to comment #17)
> > try at a minimum immutable, mutable, and inout.  If more than one of these
> > typechecks, the call is ambiguous.
> 
> What if one is a better match than the other? If it should fail I think we
> should use the repaired overload resolution. It has exactly the required
> semantics.

Example?  How can immutable match "better" than mutable?  I guess it would
depend on the definition of "better".

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #18 from timon.g...@gmx.ch 2012-02-03 17:14:50 PST ---
(In reply to comment #17)
> (In reply to comment #16)
> > (In reply to comment #13)
> > > Once again you are right Timon!
> > > 
> > > I was neglecting to see in the original example that the call was 
> > > id(foo(y))
> > > instead of just id(y)!  I sometimes cannot penetrate your inadvertent
> > > obfuscation :)  Your original example was (should have been) sufficient.
> > > 
> > 
> > OK. What measures can I take to less obfuscate my code? =)
> 
> hehe, use temporaries to demonstrate what types should be.  Or more inline
> comments maybe.  I just missed seeing the double call in one expression.
> 
> For example, this could have been more effective:
> 
> // your definition for foo
> 
> inout(int)[] id(inout(int)[] x) { return x;}
> 
> inout(const(int))[] bar(inout(int)[] x)
> {
>inout(const(int))[] tmp = foo(x);
>return id(tmp); // need to be able to call
> }
> 
> > I think what you propose would work.
> > 
> > But the overload rule I want to add (see issue 7431) is actually quite
> > intuitive and I think it is a good move to make the overload rules 
> > consistent
> > enough so that we could re-use them for inout matching. It benefits code 
> > that
> > does not use inout too.
> > 
> > Not fixing the overload rules would result in inout being _more_ powerful 
> > than
> > three overloads => inout could not be replaced by three overloads
> > transparently, if it was later determined that the different const versions
> > need different function bodies.
> 
> inout is *already* more powerful.  It guarantees no molestation, even for
> mutable args.
> 

Indeed, it gives the same guarantees as const.

> But I see your point.  I'm not opposed to fixing both, but this way of
> explaining inout is simple to me, and to someone who doesn't want to get into
> the complexities of understanding overload resolution.  In other words, one
> doesn't have to be able to understand overload resolution to understand inout.
> 

One goal of overload resolution is to be as intuitive as possible. Few
programmers who use overloading are actually intimately familiar with the rules
that govern the resolution process.

> Consequently, if the way it gets implemented is that overload resolution is
> fixed, and then inout uses that, it's not any different, but it's easier to
> explain this way (IMO).
> 

That is probably true.

> > The only difference between using the repaired overload
> > resolution and your proposal I can see is that yours introduces possible
> > disambiguation in the case of multiple alias this. I don't know if this is 
> > good
> > or bad (my initial proposal had the same characteristic).
> > 
> > inout(int)[] foo(inout(int)[] x){return x;}
> > 
> > class C{
> > int[] x(){writeln("x!");return new int[10];}
> > immutable int[] y(){writeln("y!");return new immutable(int)[10];}
> > alias x this;
> > alias y this;
> > }
> > 
> > void main(){
> > C c = new C;
> > foo(c); // should this work or fail?
> > }
> 
> I think you give me too many headaches :)  My gut says this should fail,
> because the call is not just ambiguously typed, but what you *pass* to the 
> call
> is ambiguous.  Consider this less benign example:
> 
> struct S
> {
>int[] x;
>immutable(int)[] y;
>alias x this;
>alias y this;
> }
> 
> x and y are not just generated temporaries, so the data you pass could be
> different depending on the compiler choice of what order to try the first 
> three
> type constructors.
> 
> My rules depend on the assumption that the argument type is already decided. 
> In the case of literals, that's ok, because an arbitrary choice doesn't change
> code paths, just the type of the expression.
> 
> In this case, we have to cry ambiguity, and fail to compile, in the name of
> consistency.  So how to amend my algorithm?  I suppose something like:
> 
> try at a minimum immutable, mutable, and inout.  If more than one of these
> typechecks, the call is ambiguous.

What if one is a better match than the other? If it should fail I think we
should use the repaired overload resolution. It has exactly the required
semantics.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #17 from Steven Schveighoffer  2012-02-03 
16:54:12 PST ---
(In reply to comment #16)
> (In reply to comment #13)
> > Once again you are right Timon!
> > 
> > I was neglecting to see in the original example that the call was id(foo(y))
> > instead of just id(y)!  I sometimes cannot penetrate your inadvertent
> > obfuscation :)  Your original example was (should have been) sufficient.
> > 
> 
> OK. What measures can I take to less obfuscate my code? =)

hehe, use temporaries to demonstrate what types should be.  Or more inline
comments maybe.  I just missed seeing the double call in one expression.

For example, this could have been more effective:

// your definition for foo

inout(int)[] id(inout(int)[] x) { return x;}

inout(const(int))[] bar(inout(int)[] x)
{
   inout(const(int))[] tmp = foo(x);
   return id(tmp); // need to be able to call
}

> I think what you propose would work.
> 
> But the overload rule I want to add (see issue 7431) is actually quite
> intuitive and I think it is a good move to make the overload rules consistent
> enough so that we could re-use them for inout matching. It benefits code that
> does not use inout too.
> 
> Not fixing the overload rules would result in inout being _more_ powerful than
> three overloads => inout could not be replaced by three overloads
> transparently, if it was later determined that the different const versions
> need different function bodies.

inout is *already* more powerful.  It guarantees no molestation, even for
mutable args.

But I see your point.  I'm not opposed to fixing both, but this way of
explaining inout is simple to me, and to someone who doesn't want to get into
the complexities of understanding overload resolution.  In other words, one
doesn't have to be able to understand overload resolution to understand inout.

Consequently, if the way it gets implemented is that overload resolution is
fixed, and then inout uses that, it's not any different, but it's easier to
explain this way (IMO).

> The only difference between using the repaired overload
> resolution and your proposal I can see is that yours introduces possible
> disambiguation in the case of multiple alias this. I don't know if this is 
> good
> or bad (my initial proposal had the same characteristic).
> 
> inout(int)[] foo(inout(int)[] x){return x;}
> 
> class C{
> int[] x(){writeln("x!");return new int[10];}
> immutable int[] y(){writeln("y!");return new immutable(int)[10];}
> alias x this;
> alias y this;
> }
> 
> void main(){
> C c = new C;
> foo(c); // should this work or fail?
> }

I think you give me too many headaches :)  My gut says this should fail,
because the call is not just ambiguously typed, but what you *pass* to the call
is ambiguous.  Consider this less benign example:

struct S
{
   int[] x;
   immutable(int)[] y;
   alias x this;
   alias y this;
}

x and y are not just generated temporaries, so the data you pass could be
different depending on the compiler choice of what order to try the first three
type constructors.

My rules depend on the assumption that the argument type is already decided. 
In the case of literals, that's ok, because an arbitrary choice doesn't change
code paths, just the type of the expression.

In this case, we have to cry ambiguity, and fail to compile, in the name of
consistency.  So how to amend my algorithm?  I suppose something like:

try at a minimum immutable, mutable, and inout.  If more than one of these
typechecks, the call is ambiguous.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #16 from timon.g...@gmx.ch 2012-02-03 16:26:32 PST ---
(In reply to comment #13)
> Once again you are right Timon!
> 
> I was neglecting to see in the original example that the call was id(foo(y))
> instead of just id(y)!  I sometimes cannot penetrate your inadvertent
> obfuscation :)  Your original example was (should have been) sufficient.
> 

OK. What measures can I take to less obfuscate my code? =)

> I see now that inout(const) must be a consideration for substituting inout.
> 
> Now, regarding overload resolution as it pertains to resolving what inout
> means, I still think a simple algorithm as I previously stated should work.  
> We
> just need to add inout(const) as a possible substitute.  I think the ordering
> should be something like:
> 
> mutable, immutable, inout, inout(const), const
> 
> Note that inout and inout(const) are the local version (not the wildcard
> version).  Also note that mutable, immutable, and inout could be in any order.
> 
> The algorithm I stated earlier needs to be modified.  The easiest way to state
> it is, try each of the above substitutes for inout in order, and the first one
> that type-checks, wins.  I think it works because there are no cycles in the
> implicit conversion graph:
> 
> mutable ---+
>|
> immutable --+--> inout(const) -+-> const 
> |  |
> inout --+--+
> 
> But I don't see why we need complex overload rules as you stated.  Can you 
> show a counter-example to my simple design? 

I think what you propose would work.

But the overload rule I want to add (see issue 7431) is actually quite
intuitive and I think it is a good move to make the overload rules consistent
enough so that we could re-use them for inout matching. It benefits code that
does not use inout too.

Not fixing the overload rules would result in inout being _more_ powerful than
three overloads => inout could not be replaced by three overloads
transparently, if it was later determined that the different const versions
need different function bodies.

immutable(int)[] foo(immutable(int)[] x,float){return x;}
const(int)[] foo(const(int)[] x, float){return x;}
int[] foo(int[] x,float){return x;}

inout(int)[] bar(inout(int)[] x,float){return x;}

void main(){
foo([1,2,3],4); // would not work
bar([1,2,3],4); // would work!
}


> I'd like to keep things simple, because
> inout is already difficult to understand and making it simple to explain is a
> huge benefit.

I think 'create pseudo-overloads and use the rules for overloading' is simplest
(with the additional overloading rule, so that it works), but what you propose
should work too. The only difference between using the repaired overload
resolution and your proposal I can see is that yours introduces possible
disambiguation in the case of multiple alias this. I don't know if this is good
or bad (my initial proposal had the same characteristic).

inout(int)[] foo(inout(int)[] x){return x;}

class C{
int[] x(){writeln("x!");return new int[10];}
immutable int[] y(){writeln("y!");return new immutable(int)[10];}
alias x this;
alias y this;
}

void main(){
C c = new C;
foo(c); // should this work or fail?
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #15 from Steven Schveighoffer  2012-02-03 
16:04:11 PST ---
(In reply to comment #14)
> Er... messed up that graph a smidge
> 
> (In reply to comment #13)
> > mutable ---+
> >|
> > immutable --+--> inout(const) -+-> const 
> > |  |
> > inout --+--+

Gah! I suck at ASCII graphs, immutable converts to const too, but you get my
point though :)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #14 from Steven Schveighoffer  2012-02-03 
15:59:19 PST ---
Er... messed up that graph a smidge

(In reply to comment #13)
> mutable ---+
>|
> immutable --+--> inout(const) -+-> const 
> |  |
> inout --+--+

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #13 from Steven Schveighoffer  2012-02-03 
15:46:53 PST ---
Once again you are right Timon!

I was neglecting to see in the original example that the call was id(foo(y))
instead of just id(y)!  I sometimes cannot penetrate your inadvertent
obfuscation :)  Your original example was (should have been) sufficient.

I see now that inout(const) must be a consideration for substituting inout.

Now, regarding overload resolution as it pertains to resolving what inout
means, I still think a simple algorithm as I previously stated should work.  We
just need to add inout(const) as a possible substitute.  I think the ordering
should be something like:

mutable, immutable, inout, inout(const), const

Note that inout and inout(const) are the local version (not the wildcard
version).  Also note that mutable, immutable, and inout could be in any order.

The algorithm I stated earlier needs to be modified.  The easiest way to state
it is, try each of the above substitutes for inout in order, and the first one
that type-checks, wins.  I think it works because there are no cycles in the
implicit conversion graph:

mutable +--+
|  |
immutable --+--> inout(const) -+-> const 
|  |
inout --+--+

But I don't see why we need complex overload rules as you stated.  Can you show
a counter-example to my simple design?  I'd like to keep things simple, because
inout is already difficult to understand and making it simple to explain is a
huge benefit.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #12 from timon.g...@gmx.ch 2012-02-03 14:42:21 PST ---
(In reply to comment #11)
> (In reply to comment #10)
> > For example, this should type check:
> > 
> > immutable(int)[] arr = [2,3,4];
> > inout(const(int))[] foo(inout(int)[] x){
> > return uniform(0,2) ? arr : x;
> > }
> > inout(int)[] id(inout(int)[] x){
> > return x;
> > }
> > inout(int)[] bar(inout(int)[] x){
> > inout(int)[] y = [1,2,3];
> > inout(const(int))[] z = id(foo(y)); // inout const substitute for inout
> > return z~x;
> > }
> 
> This typechecks even if we don't have inout(const) as an option:
> [snip.]
> 

My point was that it does not _if_ we have it as an option (and it has to be an
option if we want inout to be powerful enough to replace identical overloads on
const). Furthermore, foo cannot type check without inout(const) and provide the
same guarantees.

Maybe my example was not illustrative enough, second try:

immutable(int)[] arr = [2,3,4];
inout(const(int))[] foo(inout(int)[] x){
return uniform(0,2) ? arr : x;
}
inout(int)[] id(inout(int)[] x){
return x;
}
inout(const(int))[] bar(inout(int)[] x){
inout(int)[] y = [1,2,3];
return id(foo(y)); // 
}
void main(){
auto a = new int[10];
auto b = bar(a);
static assert(is(typeof(b)==const(int)[])); // !!!
auto c = new immutable(int)[10];
immutable(int)[] d = bar(c); // !!!
}

foo(y) => inout(const(int))[]
id(foo(y)) =>! inout(const(int))[]// has to use inout const as inout
substitute!

resolve inout to mutable or const:
return type inout(const(int))[] => const(int)[]

resolve inout to immutable:
return type inout(const(int))[] => immutable(int)[]



> Besides, you are assuming here that the lvalue side of the expression plays a
> role in determining the inout match.  It doesn't.  The return type is solely
> determined by the argument expressions.
> 

I don't see why you think I am.

> > There are indeed corner cases, for example:
> > 
> > void foo(immutable(int) x, float y){}
> > void foo(const(int) x, float y){}
> > void foo(int x, float y){}
> > 
> > void main(){foo(1,1);} // error, matches all three
> 
> This case has no relevance, there is no inout return value.  Who cares what
> inout resolves to?

Nobody. You claimed that the overload resolution rules are good enough to
uniquely determine what inout should resolve to in all cases, and I provided a
minimal counter-example. If you want something a little bit more concrete,
consider this:

immutable(int)[] foo(immutable(int)[] x, float f){return x;}
int[] foo(int[] x, float f){return x;}

void main(){foo([1,2,3],4);} // error

I am becoming quite confident that the overload resolution rules are the
culprit. A parameter type should be considered more specialized than another
one if it better matches the argument type. That would render the
disambiguation steps in my sketch unnecessary.

> 
> Not to be nit picky, but we should consider that any polysemous value type is
> not going to play a vital role in an inout function, since it's implicitly
> convertible to any modifier.  It's references or contained references which
> make a difference.

I was making a statement about the overload resolution rules. Those also apply
to reference types.

> 
> If it comes down to supporting this, choosing any inout match arbitrarily is
> good enough.

In this exact case, yes. In general, no.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-03 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #11 from Steven Schveighoffer  2012-02-03 
03:24:52 PST ---
(In reply to comment #10)
> For example, this should type check:
> 
> immutable(int)[] arr = [2,3,4];
> inout(const(int))[] foo(inout(int)[] x){
> return uniform(0,2) ? arr : x;
> }
> inout(int)[] id(inout(int)[] x){
> return x;
> }
> inout(int)[] bar(inout(int)[] x){
> inout(int)[] y = [1,2,3];
> inout(const(int))[] z = id(foo(y)); // inout const substitute for inout
> return z~x;
> }

This typechecks even if we don't have inout(const) as an option:
  inout matches inout (we need a new term for this 'local' inout!)
  foo(y) => inout(int)[]
  inout(int)[] => inout(const(int))[] => z

Besides, you are assuming here that the lvalue side of the expression plays a
role in determining the inout match.  It doesn't.  The return type is solely
determined by the argument expressions.

> There are indeed corner cases, for example:
> 
> void foo(immutable(int) x, float y){}
> void foo(const(int) x, float y){}
> void foo(int x, float y){}
> 
> void main(){foo(1,1);} // error, matches all three

This case has no relevance, there is no inout return value.  Who cares what
inout resolves to?

Not to be nit picky, but we should consider that any polysemous value type is
not going to play a vital role in an inout function, since it's implicitly
convertible to any modifier.  It's references or contained references which
make a difference.

If it comes down to supporting this, choosing any inout match arbitrarily is
good enough.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-02 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #10 from timon.g...@gmx.ch 2012-02-02 13:05:31 PST ---
(In reply to comment #9)
> (In reply to comment #8)
> > This rule should work satisfactory:
> > 
> > - The compiler is required to resolve inout such that the behavior is as if
> > there were four (five, with inout(const(T)) enhancement in place) separate
> > overloads. This could be implemented similar to how you propose it, by 
> > adding
> > all of the versions to the overload set, or by using some insights to speed 
> > up
> > the process (not very hard)
> 
> This sounds fine.  However, inout(const(T)) is not a substitute for inout(T),
> so it should be four.
> 

inout(const(T)) should be its own type. And as soon as that is the case, inout
const will have to be a valid substitute for inout.

For example, this should type check:

immutable(int)[] arr = [2,3,4];
inout(const(int))[] foo(inout(int)[] x){
return uniform(0,2) ? arr : x;
}
inout(int)[] id(inout(int)[] x){
return x;
}
inout(int)[] bar(inout(int)[] x){
inout(int)[] y = [1,2,3];
inout(const(int))[] z = id(foo(y)); // inout const substitute for inout
return z~x;
}


> inout(const(T)) is special in what can implicitly convert to it.  But the 
> inout
> is the only wildcard there.

True, but that does not mean it should not be a valid substitute for inout. 

> 
> The rest is not necessary.  The normal overload rules already should handle
> which one is chosen.  Since inout, mutable, and immutable do not implicitly
> convert to each other, it's not possible for there to be an ambiguity, is
> there?  immutable and mutable (and by extension inout) should be preferred 
> over
> const.

There are indeed corner cases, for example:

void foo(immutable(int) x, float y){}
void foo(const(int) x, float y){}
void foo(int x, float y){}

void main(){foo(1,1);} // error, matches all three

A different solution would be to refine the overload rules.


> 
> It's important to note that the inout overload we are talking about is not the
> wildcard inout, but the local const-like inout.

Exactly. The same holds for inout(const(T)).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-02-02 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #9 from Steven Schveighoffer  2012-02-02 
12:07:29 PST ---
(In reply to comment #8)
> This rule should work satisfactory:
> 
> - The compiler is required to resolve inout such that the behavior is as if
> there were four (five, with inout(const(T)) enhancement in place) separate
> overloads. This could be implemented similar to how you propose it, by adding
> all of the versions to the overload set, or by using some insights to speed up
> the process (not very hard)

This sounds fine.  However, inout(const(T)) is not a substitute for inout(T),
so it should be four.

inout(const(T)) is special in what can implicitly convert to it.  But the inout
is the only wildcard there.

The rest is not necessary.  The normal overload rules already should handle
which one is chosen.  Since inout, mutable, and immutable do not implicitly
convert to each other, it's not possible for there to be an ambiguity, is
there?  immutable and mutable (and by extension inout) should be preferred over
const.

It's important to note that the inout overload we are talking about is not the
wildcard inout, but the local const-like inout.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-27 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #8 from timon.g...@gmx.ch 2012-01-27 14:44:19 PST ---
This rule should work satisfactory:

- The compiler is required to resolve inout such that the behavior is as if
there were four (five, with inout(const(T)) enhancement in place) separate
overloads. This could be implemented similar to how you propose it, by adding
all of the versions to the overload set, or by using some insights to speed up
the process (not very hard)

- If there would be an ambiguity between the different pseudo overloads:
-- If one of the remaining multiple possibilities is the const version, drop it
-- If one of the possibilities is the inout version, drop it
(-- If one of the remaining multiple possibilities is the inout const version,
drop it)
-- If mutable and immutable are remaining possible matches for inout, resolve
inout to mutable.
-- otherwise resolve inout to what is left.

- Allow direct conversion of the return type to any of the versions of inout
that still match after implicit conversions of the arguments in place.

- An inout function is considered to be less specialized than a corresponding
non-inout one.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #7 from Steven Schveighoffer  2012-01-26 
10:21:28 PST ---
(In reply to comment #6)
> (In reply to comment #5)
> > Let's assume inout
> > did resolve to const for foo, and the function could be called:
> > 
> > immutable int x = 5;
> > immutable(int)* xp = &x;
> > immutable(int)** xpp = &xp;
> > 
> > const(int *)* y = foo(xpp);
> > 
> > int z = 2;
> > 
> > *y = &z; // this should pass, since I can assign int* to const(int*).
> 
> You cannot assign anything to const(int*), that is the point of const.

Oh yeah :)  Stupid me, for some reason in my head this made sense because there
was a mutable part.

> > 
> > immutable(int *)* foo(immutable(int *)* x) // inout == immutable
> > const(int *)* foo(const(int *)* x) // inout == const
> >   int **  foo(  int **  x) // inout == mutable
> > 
> > none of these can be called with immutable(int)** because there is no 
> > implicit
> > cast to the parameter.  I don't think const(immutable(int)*)* reduces to
> > const(int *)*.
> 
> It does. The second version is callable with immutable(int)**. Not fixing this
> would mean there are cases where code duplication is more expressive than
> inout.

You are right.  So we need to come up with some rules for inout as to how it
matches.

What about this idea?

for each inout parameter, we try as a substitute in order: mutable, immutable,
inout, const.  See if the argument can be implicitly converted to the
substituted parameter.

If none of the possible substitutes can be implicitly converted to for a single
parameter, the function fails to be called, and an error is generated "inout
cannot be resolved [for parameter x]"

If substitutes can be found for all of the inout parameters, and they all match
(i.e. all mutable, all immutable, all inout or all const), then that is used as
the substitute and the function is called.

If substitutes are different (e.g. one is mutable, but another is immutable),
then const is used as the substitute.  The parameters are then re-checked to
see that they all implicitly convert to the substituted const type.  If this is
not possible, an error is generated "common inout substitute cannot be found".

I think this should be as capable as duplicate functions.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #6 from timon.g...@gmx.ch 2012-01-26 09:55:37 PST ---
(In reply to comment #5)
> (In reply to comment #3)
> 
> > The typeof resolves to error because inout resolves to immutable.
> 
> As I said, it should fail to match or match mutable and fail to call.  I'm not
> sure which is correct, but I feel either way that the assert should fail.  If
> it's resolving to immutable, I think it's a bug, not because it's not passing,
> but because it's failing for the wrong reason.
> 
> I think your expectations would be a violation of const. 

No.

> Let's assume inout
> did resolve to const for foo, and the function could be called:
> 
> immutable int x = 5;
> immutable(int)* xp = &x;
> immutable(int)** xpp = &xp;
> 
> const(int *)* y = foo(xpp);
> 
> int z = 2;
> 
> *y = &z; // this should pass, since I can assign int* to const(int*).

You cannot assign anything to const(int*), that is the point of const.


> 
> assert(*xp == 2);
> z = 3;
> assert(*xp == 3); // oops!  changed data perceived as immutable!
> 
> Is there an error in my example?  I think it comes down to this:
> 
> immutable(int *)* foo(immutable(int *)* x) // inout == immutable
> const(int *)* foo(const(int *)* x) // inout == const
>   int **  foo(  int **  x) // inout == mutable
> 
> none of these can be called with immutable(int)** because there is no implicit
> cast to the parameter.  I don't think const(immutable(int)*)* reduces to
> const(int *)*.

It does. The second version is callable with immutable(int)**. Not fixing this
would mean there are cases where code duplication is more expressive than
inout.

> 
> This does take some mental effort, so I may have made a mistake :)  I hate
> double pointers...

We have:

immutable(T) is a subtype of const(T).

=> immutable(int) :< const(int)

const(T*) :< const(S*) iff const(T) :< const(S)

=> const(immutable(int)*) :< const(int*)

const(T)* :< const(S)* iff const(T) :< const(S)

=> const(immutable(int)*)* : const(int*)*

qed

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #5 from Steven Schveighoffer  2012-01-26 
09:36:01 PST ---
(In reply to comment #3)

> The typeof resolves to error because inout resolves to immutable.

As I said, it should fail to match or match mutable and fail to call.  I'm not
sure which is correct, but I feel either way that the assert should fail.  If
it's resolving to immutable, I think it's a bug, not because it's not passing,
but because it's failing for the wrong reason.

I think your expectations would be a violation of const.  Let's assume inout
did resolve to const for foo, and the function could be called:

immutable int x = 5;
immutable(int)* xp = &x;
immutable(int)** xpp = &xp;

const(int *)* y = foo(xpp);

int z = 2;

*y = &z; // this should pass, since I can assign int* to const(int*).

assert(*xp == 2);
z = 3;
assert(*xp == 3); // oops!  changed data perceived as immutable!

Is there an error in my example?  I think it comes down to this:

immutable(int *)* foo(immutable(int *)* x) // inout == immutable
const(int *)* foo(const(int *)* x) // inout == const
  int **  foo(  int **  x) // inout == mutable

none of these can be called with immutable(int)** because there is no implicit
cast to the parameter.  I don't think const(immutable(int)*)* reduces to
const(int *)*.

This does take some mental effort, so I may have made a mistake :)  I hate
double pointers...

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #4 from timon.g...@gmx.ch 2012-01-26 09:20:32 PST ---
(In reply to comment #1)
> My understanding is, each inout deduction from a function argument just like
> pattern matching.
> 
> Parameter type:   inout(  int *)*
>  Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo modifier
> --> 'inout' is deduced to 'mutable'.
>

The compiler deduces inout to _immutable_ in this case. Other than that, it
does not make much sense to talk about a mutable pseudo modifier: inout is
transitive, but such a pseudo modifier cannot be transitive.

> I think if we allow this kind of deduction, there is an ambiguous case:
> 
> inout(int) foo(inout(int**) x){ return 0; }
> void main()
> {
> immutable(int*)* x;
> foo(x);
> // inout is deduced to imuutable or const? Both conversions
> //  immutable(int*)* to immutable(int**)
> //  immutable(int*)* to const(int**)
> // are valid, so it is ambiguous.
> }

The same ambiguity is already resolved at other points in the compiler:

inout(int) foo(inout(int) x, inout(int)* y){ return 0; }

void main(){
immutable(int)* y;
foo(1, y);
}

inout is resolved to const, even though immutable would be a far better choice.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #3 from timon.g...@gmx.ch 2012-01-26 09:07:23 PST ---
(In reply to comment #2)
> (In reply to comment #1)
> > My understanding is, each inout deduction from a function argument just like
> > pattern matching.
> > 
> > Parameter type:   inout(  int *)*
> >  Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo 
> > modifier
> > --> 'inout' is deduced to 'mutable'.
> 
> The compiler should either fail to match, since inout wildcard is not applying
> to the immutable, or if it does match, it should treat foo as:
> 
> int** foo(int **x) { return x; }
> 
> This should fail to be able to be called with immutable(int)**.
> 
> The assert should fail because the typeof should resolve to Error.
> 
> I think this bug is invalid.

The typeof resolves to error because inout resolves to immutable.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355


Steven Schveighoffer  changed:

   What|Removed |Added

 CC||schvei...@yahoo.com


--- Comment #2 from Steven Schveighoffer  2012-01-26 
07:56:53 PST ---
(In reply to comment #1)
> My understanding is, each inout deduction from a function argument just like
> pattern matching.
> 
> Parameter type:   inout(  int *)*
>  Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo modifier
> --> 'inout' is deduced to 'mutable'.

The compiler should either fail to match, since inout wildcard is not applying
to the immutable, or if it does match, it should treat foo as:

int** foo(int **x) { return x; }

This should fail to be able to be called with immutable(int)**.

The assert should fail because the typeof should resolve to Error.

I think this bug is invalid.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---


[Issue 7355] inout incorrectly resolved if the same type has both mutable and immutable parts

2012-01-26 Thread d-bugmail
http://d.puremagic.com/issues/show_bug.cgi?id=7355



--- Comment #1 from Kenji Hara  2012-01-26 04:30:30 PST ---
My understanding is, each inout deduction from a function argument just like
pattern matching.

Parameter type:   inout(  int *)*
 Argument type: mutable(immutable(int)*)*  // mutable(...) is pseudo modifier
--> 'inout' is deduced to 'mutable'.

I think if we allow this kind of deduction, there is an ambiguous case:

inout(int) foo(inout(int**) x){ return 0; }
void main()
{
immutable(int*)* x;
foo(x);
// inout is deduced to imuutable or const? Both conversions
//  immutable(int*)* to immutable(int**)
//  immutable(int*)* to const(int**)
// are valid, so it is ambiguous.
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
--- You are receiving this mail because: ---