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