digitalmars.dip.ideas - Make function pointers and delegates consistent
- Quirin Schroll (62/62) Nov 20 2025 Underlying secondary theme: Make function pointer types not be
- Paul Backus (12/16) Nov 20 2025 The *most* consistent thing to do here would be to have
- Quirin Schroll (11/28) Nov 20 2025 I’ll give you that implicit invocation is an oddity, but that’s a
- Paul Backus (6/11) Nov 20 2025 It sounds to me like this is an inconsistency with `alias`, not
- Nick Treleaven (18/32) Nov 22 2025 In June I added an example showing the semantics to the
Underlying secondary theme: Make function pointer types not be
pointer types.
Function pointers are, at least in my mental model, the same as a
delegate, just with no context. This has a few immediate
downstream effects, e.g. function pointers can’t have
member-function-only attributes.
But that’s not how the D specifies them. There are a lot of
asymmetries between function pointers and delegates, which I
think a new Edition could change for the better.
This proposal would push function types (not: function
**pointer** types) into a much smaller niche.
I can’t list them all off the top of my head. A few are:
1. An `is(T == function)` checks if `T` is a function type
despite `function` denoting function pointers, but `is(T ==
delegate)` works as expected.\
In other words, `is(typeof(function() {}) == function)` fails,
but `is(typeof(delegate() {}) == delegate)` passes, and that
makes no sense whatsoever.
2. Function pointers can bind to `T*` (inferring `T` as a
function type), delegates obviously can’t.\
Syntactically speaking, that makes no sense. `T*` should only
bind to types that are *syntactically* `T*`. The fact that they
bind function pointers because they’re pointers internally
doesn’t fly: `T*` doesn’t bind class objects, but those are
internally pointers as well. I can guess the reason for that: D
has function types, but no “underlying class” type. D would be a
better language if it pretended function pointer types were not
in fact a pointer to something.
3. A function pointer `fp` can be called with `fp(…)` and
`(*fp)(…)`, a delegate `dg` can be called using `dg(…)`, but not
`(*dg)(…)`. \
There is no good reason to write `(*fp)(…)`. It’s an unwieldy C
relic, and we don’t really need to encourage it, maybe even
remove it in a future Edition. ImportC largely reduced the need
for D to be source-compatible with C.
4. On lambdas, `typeof` is a function pointer or a delegate; on a
defined function, it’s a function type. Just make it consistent
and let `typeof` return a function pointer or delegate type. \
“But can’t you just write `typeof(&f)` when `f` is a function?”
Yes, but what if `f` isn’t a specific function I know, but a
template alias parameter? Then, `typeof(f)` gives me a function
type when a defined functions is passed, and a function pointer
or delegate type if a lambda is passed. In most cases, templates
don’t care which of these it is, but if I want to inspect the
thing, I have to do needless case distinctions, also because of
issues above.
---
The bottom line is: Function types are weird and don’t interact
well with most parts of the language from parsing to semantics,
but they seep through cracks and burden the programmer with
irrelevant details whenever they show up. Let’s make them show up
less.
First of all, we should decide if we even want to have them in
the language officially. Their status seems to be:
Un(der)documented DMD feature. That’s bad. Either remove them
entirely from the language (not the compiler internals) or
promote them to be more useful: For example, a production rule
for them in the type grammar would make spelling them more
accessible (also in diagnostics). It can already be spelled as
`typeof(*int function(int) safe.init)`, but as I pointed out,
you shouldn’t dereference function pointers, so instead, add a
`__traits` or whatever.
Nov 20 2025
On Thursday, 20 November 2025 at 12:56:55 UTC, Quirin Schroll wrote:4. On lambdas, `typeof` is a function pointer or a delegate; on a defined function, it’s a function type. Just make it consistent and let `typeof` return a function pointer or delegate type.The *most* consistent thing to do here would be to have `typeof(f)` treat `f` as a function-call expression with parentheses omitted (so, equivalent to `typeof(f())`), and force the user to write `typeof(&f)` to get the function-pointer type. This would remove the special case where `typeof` sometimes treats its argument as a symbol and sometimes as an expression, and allow programmers to remove workarounds for this special case from generic code. It would also make the ` property` attribute completely redundant and easy to remove, if we want to do that in the future.
Nov 20 2025
On Thursday, 20 November 2025 at 14:13:02 UTC, Paul Backus wrote:On Thursday, 20 November 2025 at 12:56:55 UTC, Quirin Schroll wrote:I’ll give you that implicit invocation is an oddity, but that’s a problem with ` property`’s design. The ` property` annotation aside, `&` and `typeof` both don’t implicitly invoke the outermost symbol. That is consistent. I already explained how this solution is annoying and cumbersome. If you have an alias `f`, then currently, `typeof(&f)` is a function pointer if `f` is a function and would be a pointer to function pointer or pointer to delegate if `f` is a lambda. The right way to do it is to make `typeof` never return a function type and always “promote” those to function pointers.4. On lambdas, `typeof` is a function pointer or a delegate; on a defined function, it’s a function type. Just make it consistent and let `typeof` return a function pointer or delegate type.The *most* consistent thing to do here would be to have `typeof(f)` treat `f` as a function-call expression with parentheses omitted (so, equivalent to `typeof(f())`), and force the user to write `typeof(&f)` to get the function-pointer type. This would remove the special case where `typeof` sometimes treats its argument as a symbol and sometimes as an expression, and allow programmers to remove workarounds for this special case from generic code. It would also make the ` property` attribute completely redundant and easy to remove, if we want to do that in the future.
Nov 20 2025
On Thursday, 20 November 2025 at 14:46:45 UTC, Quirin Schroll wrote:I already explained how this solution is annoying and cumbersome. If you have an alias `f`, then currently, `typeof(&f)` is a function pointer if `f` is a function and would be a pointer to function pointer or pointer to delegate if `f` is a lambda.It sounds to me like this is an inconsistency with `alias`, not an inconsistency with `typeof`. I don't think we should be adding more special cases to `typeof` to compensate for inconsistencies elsewhere in the language.
Nov 20 2025
On Thursday, 20 November 2025 at 12:56:55 UTC, Quirin Schroll wrote:1. An `is(T == function)` checks if `T` is a function type despite `function` denoting function pointers, but `is(T == delegate)` works as expected.\ In other words, `is(typeof(function() {}) == function)` fails, but `is(typeof(delegate() {}) == delegate)` passes, and that makes no sense whatsoever.In June I added an example showing the semantics to the *IsExpression* spec. Yes this is confusing and somewhat bug-prone. It also confused someone writing docs for `std.traits.isFunction` which didn't get fixed from 2016 until now: https://github.com/dlang/phobos/pull/10904 This could be remedied by having `__traits(isFunction, X)` and deprecating/discouraging use of `is(X == function)`. ...The bottom line is: Function types are weird and don’t interact well with most parts of the language from parsing to semantics, but they seep through cracks and burden the programmer with irrelevant details whenever they show up. Let’s make them show up less.Removing function types is an interesting idea, but I'm not sure that it's worth the (likely?) breakage of existing code that uses the existing type semantics to determine when a symbol is actually a function vs a function pointer. I don't know that this is enough of an issue to do it even in an edition.First of all, we should decide if we even want to have them in the language officially. Their status seems to be: Un(der)documented DMD feature.Any suggestions on how to improve the docs? https://dlang.org/spec/type.html#functions
Nov 22 2025









Paul Backus <snarwin gmail.com> 