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