www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - What should delegates with qualifiers mean?

reply Q. Schroll <qs.il.paperinik gmail.com> writes:
As per the grammar, a delegate can carry member function 
attributes, including qualifiers (const, immutable) that 
seemingly apply to the context. The spec does not speak about 
this.

We should give this meaning!

The best way to approach this mentally is through dg = 
&obj.method because the version where the delegate is from 
binding variables is more difficult.

If obj is const or immutable, &obj.method should yield a 
delegate(...) const or delegate(...) immutable. Intuitively,
* const means that the function pointed to will not change the 
object.
* immutable means that the context cannot change (implying that 
that the function pointed to will not change the object).
* mutable, i.e. no annotation, means that the context could 
change by calling the pointed-to function or through other 
actions.

While everywhere else, immutable is a requirement and a 
guarantee, here it is a guarantee only. That is because the 
context object cannot be reassigned independently of the function 
pointer. Therefore, a `delegate() immutable` is convertible to a 
`delegate() const` delegate which in turn is convertible to a 
`delegate()`.

One benefit of fixing this is that pure immutable delegates are 
referentially transparent while pure const ones almost aren't and 
pure mutable ones carry almost no guarantees.

For delegates that come from binding local values, if all those 
values are immutable, the delegate can be inferred immutable; if 
all those values are const, the delegate can be inferred const.

I had a conversation with Timon Gehr about this and I think this 
needs a little more attention.
Mar 24
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 24 March 2021 at 19:23:15 UTC, Q. Schroll wrote:
 While everywhere else, immutable is a requirement and a 
 guarantee, here it is a guarantee only. That is because the 
 context object cannot be reassigned independently of the 
 function pointer. Therefore, a `delegate() immutable` is 
 convertible to a `delegate() const` delegate which in turn is 
 convertible to a `delegate()`.
No, this is unsound, because a delegate may return a pointer or reference to its context. Consider: struct S { int n; int* getPtr() { return &n; } } void main() safe { immutable S s = { 123 }; // implicitly convert from `delegate() immutable` to `delegate()` int* delegate() dg = &s.getPtr; // undefined behavior *dg() = 456; }
Mar 24
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 24.03.21 22:56, Paul Backus wrote:
 struct S
 {
      int n;
      int* getPtr() { return &n; }
 }
 
 void main()  safe
 {
      immutable S s = { 123 };
      // implicitly convert from `delegate() immutable` to `delegate()`
      int* delegate() dg = &s.getPtr;
      // undefined behavior
      *dg() = 456;
 }
This is not what was explained in the OP. Removing context qualifiers from delegates is sound. You are calling a mutable method on an immutable object. Not the same thing, and obviously unsound. Why is removing qualifiers sound? delegate is an existential type: B delegate(A)q ≡ ∃C. (A×q(C)*)→B Therefore, B delegate(A)immutable ≡ ∃C. (A×immutable(C)*)→B ⊆ ∃C'. (A×C'*)→B, where we have chosen C' as immutable(C).
Mar 24
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 24.03.21 23:18, Timon Gehr wrote:
 
 Why is removing qualifiers sound? delegate is an existential type:
 
 B delegate(A)q ≡ ∃C. (A×q(C)*)→B
Oops. Typo. This should of course have been: Why is removing qualifiers sound? delegate is an existential type: B delegate(A)q ≡ ∃C. (A×q(C)*)×q(C)*→B Therefore, B delegate(A)immutable ≡ ∃C. (A×immutable(C)*)×immutable(C)*→B ⊆ ∃C'. (A×C'*)×C'*→B, where we have chosen C' as immutable(C).
Mar 24
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 25.03.21 02:01, Timon Gehr wrote:
 Why is removing qualifiers sound? delegate is an existential type:
 
 B delegate(A)q ≡ ∃C. (A×q(C)*)×q(C)*→B
 
 ...
x). This is getting a bit embarrassing. Third try: Why is removing qualifiers sound? delegate is an existential type: B delegate(A)q ≡ ∃C. (A×q(C)*→B)×q(C)* Therefore, B delegate(A)immutable ≡ ∃C. (A×immutable(C)*→B)×immutable(C)* ⊆ ∃C'. (A×C'*→B)×C'*, where we have chosen C' as immutable(C).
Mar 24
prev sibling parent Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 24 March 2021 at 19:23:15 UTC, Q. Schroll wrote:
 As per the grammar, a delegate can carry member function 
 attributes, including qualifiers (const, immutable) that 
 seemingly apply to the context. The spec does not speak about 
 this.
don't forget shared! see https://issues.dlang.org/show_bug.cgi?id=21737 https://issues.dlang.org/show_bug.cgi?id=19984
Mar 24