digitalmars.D - What should delegates with qualifiers mean?
- Q. Schroll (31/31) Mar 24 2021 As per the grammar, a delegate can carry member function
- Paul Backus (17/23) Mar 24 2021 No, this is unsound, because a delegate may return a pointer or
- Timon Gehr (9/23) Mar 24 2021 This is not what was explained in the OP. Removing context qualifiers
- Timon Gehr (8/12) Mar 24 2021 Oops. Typo. This should of course have been:
- Timon Gehr (8/13) Mar 24 2021 x). This is getting a bit embarrassing. Third try:
- Nicholas Wilson (4/8) Mar 24 2021 don't forget shared! see
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 2021
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 2021
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 2021
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)*)→BOops. 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 2021
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 2021
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 2021