Thread overview
[Issue 7542] New: inout parameter contravariant should be allowed
Feb 19, 2012
Kenji Hara
Feb 19, 2012
Kenji Hara
Feb 19, 2012
timon.gehr@gmx.ch
Feb 19, 2012
Kenji Hara
Mar 09, 2012
Boscop
Mar 09, 2012
Boscop
February 19, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=7542

           Summary: inout parameter contravariant should be allowed
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: enhancement
          Priority: P2
         Component: DMD
        AssignedTo: nobody@puremagic.com
        ReportedBy: k.hara.pg@gmail.com
        Depends on: 7105


--- Comment #0 from Kenji Hara <k.hara.pg@gmail.com> 2012-02-19 03:31:38 PST ---
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; });

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 19, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=7542


Kenji Hara <k.hara.pg@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull


--- Comment #1 from Kenji Hara <k.hara.pg@gmail.com> 2012-02-19 04:39:47 PST ---
https://github.com/D-Programming-Language/dmd/pull/735

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 19, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=7542


timon.gehr@gmx.ch changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |timon.gehr@gmx.ch


--- Comment #2 from timon.gehr@gmx.ch 2012-02-19 05:05:58 PST ---
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

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
February 19, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=7542



--- Comment #3 from Kenji Hara <k.hara.pg@gmail.com> 2012-02-19 06:11:25 PST ---
(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.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 09, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=7542


Boscop <kingboscop@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |kingboscop@gmail.com


--- Comment #4 from Boscop <kingboscop@gmail.com> 2012-03-09 10:46:41 PST ---
(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).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 09, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=7542



--- Comment #5 from Boscop <kingboscop@gmail.com> 2012-03-09 11:18:18 PST ---
(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.

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