3 ms·
It’s not a question of ISA support. If you call via a function pointer, how do you supply the pointer to the data? (It has to either be in a separate place from
by klodolph 1mo ago
It’s not a question of ISA support. If you call via a function pointer, how do you supply the pointer to the data? (It has to either be in a separate place from the function code, or the same place. One requires an ABI change, the other an executable, writable section of memory.)
- WalterBright 1mo ago> If you call via a function pointer, how do you supply the pointer to the data? D has the notion of a "delegate", which is a (function pointer) and (context pointer) pair. This is incredibly useful, because delegates can: 1. call nested functions that need a pointer to the stack frame of the nestee function 2. call member functions that need `this` pointer 3. call lambdas 4. call COM member functions The neato thing about this is the ABI for delegates is all the same, so a function that gets a delegate parameter will work with any of 1..4. It's one of the most used features of D.
- klodolph 1mo agoYes, that’s the “ABI” alternative that I was referring to.
- uecker 1mo agoThis is why I want to have such a feature in C. It would be extremely useful for language interoperability. But because ISA was mentioned, x86 does indeed even have native support for this: https://devblogs.microsoft.com/oldnewthing/20231211-00/?p=109126 https://devblogs.microsoft.com/oldnewthing/20231211-00/?p=10... These instructions are not too useful though and I do not think anybody uses them.
- klodolph 1mo agoThis feature would IMO violate the contract that C allows you to specify memory layout of objects, to some level of detail (I am being a little vague about the “level of detail”). Supporting closures, more or less, requires design decisions that are equivalent to choosing a specific layout for objects in an object-oriented language. C, as it is, makes none of these assumptions and you can translate a lot of different language ABIs into some C code (that may be clumsy). Keeping the abstraction that function pointers = pointers to entry points for functions, well, that’s frustrating for C programmers writing C programs, but extremely useful for interoperability.
- uecker 1mo agoAt the moment we can not call nested functions or other things from other language from C, which is a pretty big hole in our interoperability story. I do not see why we need to make any design decision to specify object layout, we simply need a code pointer and static chain pair, which would then be sufficient to call arbitrary entities from other languages.
- klodolph 1mo ago> I do not see why we need to make any design decision to specify object layout > we simply need a code pointer and static chain pair The code pointer and chain pair needs an object layout. You would have to pick a specific layout, and it would not be compatible with other languages that have a different layout. Right now I can do this: struct a { void (*fun)(void *ctx); int data1; int data2; }; struct b { void (*fun)(void *ctx); void *ctx; }; And I could call them: struct a *aptr; a->fun(aptr); struct b *bptr; b->fun(bptr->ctx); There is only one neutral, maximally compatible option here—which is to have the function pointer separate from the arguments you want to pass in, and pass them in explicitly. If you add closures to C you are making compatibility worse, not better.
- uecker 1mo agoExcept doing this manually does not allow me to directly call a C++ lambda, a Go closure, an Ada closure etc which I can not even express in C. So compatibility can not become worse, it is already maximally bad. And even where you can build a compatible solution in C, there are now different choices. Your examples already directly shows this contradicting your claim that here is only one option. Adding such a type as a vocabulary type would fix all this. You can argue that we fix an object layout for a pointer pair, but this seems an acceptable trade-off to me. This seems far from your previous claim that this "requires design decisions that are equivalent to choosing a specific layout for objects in an object-oriented language." Note also that such a type can always adapt to different calling conventions of other languages by using the address of a static thunk as code pointer so it is very generic.
- deleted 1mo ago[deleted]
- QuadmasterXLII 1mo agobut that can just be executable heap?
- klodolph 1mo agoYes, but the advice was W^X. Either a page of memory is executable or writable but not both at the same time.