Uncallable delegates
Dukc
ajieskola at gmail.com
Mon Oct 26 11:19:12 UTC 2026
On Thursday, 22 October 2026 at 23:34:43 UTC, Walter Bright wrote:
> On 4/1/2026 7:29 AM, Dukc wrote:
>> I have (finally) finished my DIP draft for the [Delegates and
>> qualifier
>> transitivity](https://forum.dlang.org/thread/gbrwklyugksqbpksgmgp@forum.dlang.org) idea discussion.
>>
>> It can be found
>> [here](https://gist.github.com/dukc/0ede11a0fcb77b2ff92654ceaa7805e2), and is awaiting your feedback.
>
> Calling std library functions makes the DIP harder to
> understand. Also, examples that contain more than one qualifier
> become very hard to understand.
>
> A more understandable DIP would deal with only one qualifier at
> at time - can it be implicitly converted or not, and does it
> apply to the function pointer or the context pointer?
I can't edit the DIP since it's in formal assessment, but here's
the translation of the examples in "current rules and their
shortcomings" to your preferences. As you can see, the troubles
do trigger without a single `cast` operator:
```D
struct S
{ int field;
int getField() const => field;
void increment(){field++;}
}
int[2] constMutatesContext()
{ S s;
int[2] result;
const del = &s.increment;
result[0] = s.field;
// the delegate is const. D const is transitive, so the
context
// should also be const and not change, right?
del();
result[1] = s.field;
// DMD returns [0, 1]
return result;
}
int[2] immutableRefersToMutable()
{ S s;
int[2] result;
immutable int delegate() immutable del = &s.getField;
result[0] = del();
s.field++;
// The delegate and it's context are both immutable, so this
should
// be the same as result[0], right?
result[1] = del();
// DMD returns [0, 1]
return result;
}
```
You can add `@safe` and/or `pure` to all the delegates and
functions, and it still compiles and runs the same.
As for the proposed changes, I don't see how I could write them
simpler. Look at the existing [qualifier conversion
rules](https://dlang.org/spec/const3.html#implicit_qualifier_conversions): you can't specify those one qualifier at a time either, since they fundamentally deal with qualifier sets, not qualifiers in isolation.
The DIP already has separate sections for the proposed changes
for function pointer qualifiers and context pointer qualifier
rules (called context qualifiers and outer qualifiers
respectively by the dip, see the terminology section), precisely
because they are simpler to deal with in isolation.
>
> Whether such calls can be done in @safe or @system should not
> be a factor. For example, a pointer to a const cannot modify
> the const in @system code. @system code would allow an explicit
> cast to mutable.
This is not changing. Explicit casts are the only thing `@safe`
will turn from valid code to errors.
Now, in legacy code, `@safe` will have some implicit casts (and
also calls) emit warnings that would quietly compile without the
attribute. This is for code that would be outright disabled
without an explicit cast under rules of a bleeding edge edition.
I could have specified that those emit warning regardless of
`@safe`, or that they never emit warnings, but I felt this is the
best compromise. `@safe` simply doesn't do what it's designed to
do if you use those constructs, so I felt it's too dangerous to
let them pass compilation quietly in safe code. On the other
hand, I know you hate warnings so I wanted to minimise them by
speccing that they don't happen for non-`@safe` code.
Of course, you're obliged to accept or reject the DIP as is. If
you insist on no warnings or more warnings, you can just decide
so (I think. Ask Mike if you're not sure).
More information about the dip.development
mailing list