Bug 7542 – inout parameter contravariant should be allowed

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2012-02-19T03:31:38Z
Last change time
2024-12-13T17:58:34Z
Assigned to
No Owner
Creator
Kenji Hara
Depends on
7105
Moved to GitHub: dmd#18416 →

Comments

Comment #0 by k.hara.pg — 2012-02-19T03:31:38Z
After fixing issue 7105, we should allow inout parameter covariant. Test cases: ---- void function(int* p) mfp; void function(const(int)* p) cfp; void function(immutable(int)* p) ifp; void function(inout(int)* p) wfp; wfp = mfp; wfp = cfp; wfp = ifp; static assert(!__traits(compiles, wfp = function void(int**){})); static assert(!__traits(compiles, wfp = function void(int[]){})); void delegate(int* p) mdg; void delegate(const(int)* p) cdg; void delegate(immutable(int)* p) idg; void delegate(inout(int)* p) wdg; wdg = mdg; wdg = cdg; wdg = idg; static assert(!__traits(compiles, wdg = delegate void(int**){})); static assert(!__traits(compiles, wdg = delegate void(int[]){})); void foo(T)(void delegate(inout(int)** p, inout(int)* v) dg) { T* pm; T m; dg(&pm, &m); assert(pm == &m); } foo!( int)(( int ** p, int * v){ *p = v; }); foo!( const int)(( const(int)** p, const(int)* v){ *p = v; }); foo!(immutable int)((immutable(int)** p, immutable(int)* v){ *p = v; });
Comment #1 by k.hara.pg — 2012-02-19T04:39:47Z
Comment #2 by timon.gehr — 2012-02-19T05:05:58Z
This pull breaks the type system: void main(){ // conversion from void function(int*) to void function(inout(int)*): void function(inout(int)*) wfp = function(int*)(*p = 1;} immutable int x = 0; wfp(&x); // mutates x } The title of the bug report is correct though, contravariance is safe. Those are the safe conversions: mfp = wfp; // match inout as mutable wfp = cfp; // inout is a subtype of const cfp = wfp; // match inout as const ifp = wfp; // match inout as immutable
Comment #3 by k.hara.pg — 2012-02-19T06:11:25Z
(In reply to comment #2) > This pull breaks the type system: > > void main(){ > // conversion from void function(int*) to void function(inout(int)*): > void function(inout(int)*) wfp = function(int*)(*p = 1;} > immutable int x = 0; > wfp(&x); // mutates x > } > > The title of the bug report is correct though, contravariance is safe. > > Those are the safe conversions: > mfp = wfp; // match inout as mutable > wfp = cfp; // inout is a subtype of const > cfp = wfp; // match inout as const > ifp = wfp; // match inout as immutable You are right, and this fix doesn't block 7543.
Comment #4 by kingboscop — 2012-03-09T10:46:41Z
(In reply to comment #2) > This pull breaks the type system: > > void main(){ > // conversion from void function(int*) to void function(inout(int)*): > void function(inout(int)*) wfp = function(int*)(*p = 1;} You can't do that because void function(int*) is a supertype of void function(inout(int)*). (as I described in comment 4 of bug 7543). One wants to be able to do: void fooM(int*); void fooC(const(int)*); void fooI(immutable(int)*); void function(const(int)*) wfp; wfp = &fooM; wfp = &fooC; wfp = &fooI; This is only possible when the following subtyping rules are obeyed: T <: const(T) immutable(T) <: const(T) And we also have: T* <: const(T)* immutable(T)* <: const(T)* ( And btw: T* <: const(T)* <: const(T*) immutable(T)* <: immutable(T*) <: const(T*) ) And of course the usual function subtyping rules (types of in-arguments are contravariant and types of out-arguments and return types are covariant).
Comment #5 by kingboscop — 2012-03-09T11:18:18Z
(In reply to comment #4) > void fooM(int*); > void fooC(const(int)*); > void fooI(immutable(int)*); > void function(const(int)*) wfp; > wfp = &fooM; > wfp = &fooC; > wfp = &fooI; Sorry, this was wrong, that would allow modifying the arg in fooM. And it wouldn't work because int* is not a supertype of const(int)* but a subtype. If you want the arg to be mutable, you'd want to do: void fooM(int*); void fooC(const(int)*); void fooI(immutable(int)*); void function(int*) wfp; wfp = &fooM; wfp = &fooC; wfp = &fooI; The last case doesn't work because immutable(T) is not a supertype of T. But if you have a void fooIO(inout(int)*); you could do wfp = &fooIO; because inout(T) is a supertype of T. If you want void function(const(int)*) wfp; only these work: wfp = &fooC; wfp = &fooIO; fooM doesn't work because T is not a supertype of const(T) Makes sense because you don't want to modify a const object. fooI doesn't work because immutable(T) is not a supertype of const(T) Makes sense because immutable functions assume that the arg is not modified elsewhere.
Comment #6 by verylonglogin.reg — 2014-01-02T04:37:42Z
Looks like another dup of INVALID-ated Issue 3075 about parameter contravariance.
Comment #7 by robert.schadek — 2024-12-13T17:58:34Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/18416 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB