Uncallable delegates
Walter Bright
newshound2 at digitalmars.com
Tue May 12 04:29:12 UTC 2026
On 4/1/2026 7:29 AM, Dukc wrote:
> It can be found
> [here](https://gist.github.com/dukc/0ede11a0fcb77b2ff92654ceaa7805e2), and is
> awaiting your feedback.
Thank you for your hard work on this. It's an important thing to get right.
The difficulty I have with it is I do not understand it. It has to be broken
down into simpler constructs, then built back up into the delegate. How
delegates behave is inevitable, it is something that we either get right or get
severely wrong.
** Implicit Conversions
Let's start with implicit conversions:
```
int* p;
const(int)* q;
p = q; // invalid
q = p; // valid (contravariance)
```
What is important here is all of the type qualifiers add a *restriction*. None
of the the type qualifiers *loosen* it. So the implicit conversions only go one
way, like a diode.
** Class Inheritance
The next concept is covariance:
```
class A {
void foo(int*);
void bar(const(int)*);
}
class B : A {
void foo(const(int)*); // ok - added restriction, covariant
void bar(int*); // error, removed restriction
}
```
Since B.foo overrides A.foo, it must adhere to the (int*) constraint, and since
nothing says A.foo must modify through the parameter, overriding it with B.foo
that promises to not change it, still fulfills the (int*).B.bar() is an error
because it does not fulfill the promise of A.bar() that the argument won't be
modified. This is called covariance.
Next, contravariance:
```
class A {
int* foo();
const(int)* bar();
}
class B {
const(int)* foo(); // error, as the return value gets interpreted as mutable
int* bar(); // ok, as the return result can be implicitly cast to const
}
```
This property is called contra-variance.
** Function Pointers
```
int* function() foop;
const(int)* function() barp;
barp = foop; // ok, contravariant, foop()'s return is cast to const(int)*
foop = barp; // error, barp's return is cast to mutable
```
** Delegates
Delegates are a function pointer with an additional (hidden) parameter.
```
int* delegate() foodg;
```
For illustration purposes, it can be rewritten as a function pointer with the
additional (hidden) parameter explicit, let's call it `this`:
```
int* function(const(int)* this) foodg;
```
Apply the rules for return types for function pointers, and the covariant rules
for the `this` parameter, and the behavior of delegates is completely derived
from the earlier rules. We are not designing anything new.
*** Type Qualifiers for Delegates
```
const T* delegate() dg; // the const applies to the function pointer
const(T)* delegate() dg; // the const(T)* is the type of the return value
void delegate() const dg; // the const is applied to the `this` parameter
```
It is not necessary for the DIP to address any storage classes or attributes
other than simply use `pure` for storage class and `const` for attribute. The
behavior of the other storage classes (like nothrow, @nogc) is the same. The
same for other attributes (immutable, @safe, nothrow, etc.)
Feel free to use any or all of this in your DIP.
More information about the dip.development
mailing list