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