Uncallable delegates
Timon Gehr
timon.gehr at gmx.ch
Sat May 16 07:20:02 UTC 2026
On 5/16/26 08:47, Walter Bright wrote:
> On 5/15/2026 9:55 PM, Dukc wrote:
>> I will analyse your class inheritance analogy later when I have more
>> time, likely this evening. But, if I understand right, your
>> reservations are specifically about the conversion rules. Are you
>> already sold on the need to make some delegates uncallable, or do you
>> have also have some other concerns regarding them?
>
> My concern is this problem is a problem with the implicit conversion of
> a delegate to `pure`.
There is no implicit conversion of a delegate to `pure` in the example.
> I suggest that problem get fixed before going any
> further with this. The reason is the bug examples seem to rely on such
> an implicit conversion.
> ...
No, the example I gave you just relies on the result of a `pure`
function call being implicitly convertible to `immutable`. There is no
implicit conversion of a delegate type to `pure`, you clearly did not
actually look into it at all. Why are you not looking at the example? It
is short.
> If the same problem can be demonstrated without using pure attributes,
> then it is a problem separate from the `pure` inheritance issue.
> ...
The premise is false, and the implication only goes in one direction.
> Forgive me for asserting that many, many of the issues that have been
> posted to bugzilla turned out to not be the problem the submitter
> thought it was, but something unexpected which was revealed when the
> problem submission was pared down to a minimal example.
I gave you a minimal example for the `immutable` case. This case
requires a `pure` factory function, because that is the only `@safe` way
to get an `immutable` reference from something that used to be mutable.
The same type system unsoundness exists for `const`.
However, as far as I understand, the optimizer does not optimize based
on `const` UB (and even then it would probably additionally rely on
`pure` for alias analysis and distract you), so I can't give you an
executable `2+2 == 5` case.
The best I can do right now is show you that the delegate type checking
is different from classes:
```d
@safe:
struct T{
int* delegate() dg;
int* q;
}
T foo(){
auto x = new int(2);
auto dg = ()=>x;
return T(dg,x);
}
void main(){
const ps = foo();
static assert(is(typeof(ps.dg)==const));
auto p = ps.dg();
static assert(is(typeof(p)==int*)); // `const` removed
}
```
Here is what it will do with a class instead of a delegate:
```d
@safe:
class C{
int* x;
this(int* x){ this.x=x; }
int* call(){
return x;
}
}
struct T{
C dg;
int* q;
}
T foo(){
auto x = new int(2);
auto dg = new C(x);
return T(dg,x);
}
void main(){
const ps = foo();
static assert(is(typeof(ps.dg)==const));
auto p = ps.dg.call(); // error
//static assert(is(typeof(p)==int*)); // `const` removal not allowed
}
```
More information about the dip.development
mailing list