[Issue 7543] inout opApply should work properly

d-bugmail at puremagic.com d-bugmail at puremagic.com
Fri Mar 9 16:21:23 PST 2012


http://d.puremagic.com/issues/show_bug.cgi?id=7543



--- Comment #12 from Boscop <kingboscop at gmail.com> 2012-03-09 16:21:28 PST ---
(In reply to comment #7)
> (In reply to comment #6)
> > (In reply to comment #5)
> > > (In reply to comment #4)
> > 
> > You can't do:
> > A delegate(inout(A)) dg = (immutable(A) a) => new B(a);
> 
> You claimed I could.
> 
> Boskop wrote:
> > B delegate(immutable(A)) <: A delegate(inout(A))

This is wrong, I didn't realize that I accidentally wrote that, sorry.
What I wrote above this (and in comment 6) was right:

Given R2 <: R1,
R2 delegate(inout(T)) <: R1 delegate(immutable(T))
(because of argument contravariance and immutable(T) <: inout(T)).

I didn't know at first that you wanted to point this out (probably was too
distracted by your code example).

(In reply to comment #8)
> I think the claim that the reporter is actually making is that the inout
> constancy of the delegate parameter should vary with that of this.  In other
> words,
> 
>     int opApply(int delegate(ref inout(int)) dg) inout
> 
> should be callable as if it's any one of these:
> 
>     int opApply(int delegate(ref int) dg)
>     int opApply(int delegate(ref const(int)) dg) const
>     int opApply(int delegate(ref immutable(int)) dg) immutable

The problem is more deep-rooted. You can only pass delegates to opApply that
take a supertype of "ref inout(int)" as argument, but immutable(T) <: inout(T)
and const(T) <: inout(T), and T <: inout(T).

If it were possible to use inout that way, you would have to enable implicit
casts from T to immutable(T) (T <: immutable(T)) but you can't do that because
functions taking an immutable arg assume that it's not changed outside!
There is no way to have inout delegates like you want without enabling implicit
casts from T to immutable(T)!

But we don't need to enable implicit casts from T to immutable(T).

We can have our cake and eat it, too!

Now this is the important thing to notice:
In the case with opApply you actually want to transfer the constness of the
this object to the argument to dg!

foreach (e; new immutable(C)([1,2,3])) opApply takes ONLY a "int opApply(int
delegate(ref immutable(int)) dg) immutable"
foreach (e; new const(C)([1,2,3])) opApply takes ONLY a "int opApply(int
delegate(ref const(int)) dg) const"
foreach (e; new C([1,2,3])) opApply takes ONLY a "int opApply(int delegate(ref
int) dg)"

So we need a way to transfer the constness of the this object to declarations
within the class. This is basically inout for types (inout_t). (It's related to
the inout that is written after method signatures, but can now be be
transferred to arbitrary declarations).

So, with inout_t you would write:
class C {
    int[] arr;
    this(int[] a){arr = a;}
    int opApply(int delegate(ref inout_t(int)) dg) inout {
        foreach(ref e; arr)
            if(auto r = dg(e)) return r;
        return 0;
    }
}

BTW: If D didn't have transitive const, you could implement it with inout_t
like this:
struct S{inout_t(S)* next;}

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


More information about the Digitalmars-d-bugs mailing list