[Issue 1983] Delegates violate const

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Feb 4 12:03:55 UTC 2021


https://issues.dlang.org/show_bug.cgi?id=1983

--- Comment #27 from timon.gehr at gmx.ch ---
(In reply to Bolpat from comment #26)
> (In reply to timon.gehr from comment #25)
> > > It's even hard to pin-point which exact part of the code should be an error.
> > 
> > The problem is that you shouldn't be able to call "dg" in "kaboom", as its
> > type is `const(void delegate()pure)`. It would have to be at least something
> > like `const(void delegate()pure const)`.
> 
> My position is that distinguishing delegates for mutability of the context
> is a bad idea.

No, it's just the obvious way it has to be type checked, because the delegate
context is covariant, but the delegate argument is contravariant.

struct DG{
    void function(Ctx* ctx) dgptr;
    Ctx* ctxptr;
}

DG a;
a.dgptr(a.ctxptr); // ok
const(DG) b;
b.dgptr(b.ctxptr); // error

Delegates are not above documented type system guarantees.

The analogy above is not perfect, because the delegate type `B delegate(A)q` is
actually an existential type `∃C. q(C)×(A×q(C)→B)` with an evaluation map
`ev[A,B,q]: (∃C. q(C)×const(A×q(C)→B))×A→B`, but this aspect remains the same:

`const(∃C. q(C)×(A×q(C)→B)) = ∃C. const(q(C))×const(A×q(C)→B)`.

You can't instantiate the evaluation map with any arguments `[A,B,q]` that
makes it accept arguments of type `(∃C. const(q(C))×const(A×q(C)→B))×A` unless
`q` includes `const` (or `immutable`).

However, we still have `B delegate(A)q ⊆ B delegate(A)` because:

`B delegate(A)q = ∃C. q(C)×(A×q(C)→B) ⊆ ∃C'. C'×(A×C'→B) = B delegate(A)`,

where I have set `C'=q(C)`. Delegate contexts are not magic, they are just an
opaque pointer to data. Where exactly do you disagree?

> Thinking about it for a while, I come to the conclusion the
> problem is elsewhere, namely uniqueness deduction is broken:
> 
> >         this(int value) pure
> >         {
> >             this.value = value;
> >             this.dg = &this.mut;
> >         }
> 
> The mere fact that the struct has a delegate field means a reference to it
> *can* exist in it. Therefore, the result of the constructor cannot be
> assumed to be unique.

Sure, there can be an internal reference. That's by design. However, everything
that is not immutable is newly allocated memory and the only way to reach it is
through the constructor's result.

> The implicit cast to immutable is invalid.

No, it's perfectly fine due to the transitivity of immutable. Even if that
implicit cast was not allowed, the type system would be broken, it would just
be less obvious.

> IMO, the way the type system currently works, this is the issue.
> ...

The type checking of delegates is unsound, because it allows implicit unsafe
type coercion in the wrong direction, from supertype to subtype.

Pure functions can't change `const` arguments. Implicit hiding of mutation
capabilities within `const` structures was never part of the design, and
delegate contexts are not exempt from sound type checking.

> ...
> 
> > void main()pure{
> >     immutable a=new A(0); // pure constructor, so this is okay
> 
> "pure constructor, so this is okay": That's where the bad stuff begins.
> Uniqueness isn't just slapping pure on stuff. A pure delegate need not
> return a unique result as it can use its context to get its result from.
> That's basically what happens here.
> 
> Requiring const or immutable annotations on delegates for the context is a
> breaking change and hell is it breaking.

Just for `const` or `immutable` delegates. The annotations are not required to
call a mutable delegate, you can still remove context qualifiers from mutable
delegates as much as you wish, because the context is opaque.

This will still work just fine:

immutable int x=3;
void delegate()immutable dg = ()immutable => x;
void delegate() dg2 = dg;

Not sure what your issue is. Is there really a lot of code out there that cares
about annotating data const/immutable, yet relies on buggy delegate type
checking to bypass the annotations? Those projects should not annotate in the
first place.

--


More information about the Digitalmars-d-bugs mailing list