digitalmars.D - Typecasting delegates
- Seiji Emery (40/40) Jun 02 2017 Hi, bit of a long-time lurker here.
- Moritz Maxeiner (18/33) Jun 02 2017 It works for me, but if you're asking in terms of spec: I don't
- Mike B Johnson (3/9) Jun 03 2017 His computer could expode! Or it could trigger a black hole near
- H. S. Teoh via Digitalmars-d (10/13) Jun 02 2017 [...]
- Jacob Carlborg (6/9) Jun 03 2017 As long as you cast between different type of delegates I don't think it...
Hi, bit of a long-time lurker here. I had a few questions about D delegates: first, D delegates are the size of two pointers (16 bytes) on my machine, so I'd assume that they're implemented as a pair of pointers; presumably a C function pointer, and a GC-managed payload / context / this pointer – is this correct? Secondly, is it safe to typecast delegates for storage purposes – ie. cast `void delegate (ref Foo)` to `void delegate()`, or something similar? Since delegates seem to just be a pair of pointers, it seems like this should work; it's perfectly safe to cast C function pointers, for instance, provided that they're cast back to the correct type before actually being called. The main worry that I have is that this could somehow wreak havoc with the GC-managed payload pointer, but I'm not sure. It seems like this shouldn't be a problem since payloads change between delegates anyways (reference to object vs reference to function scope), and delegates with different signatures could point to the same object / scope – ie. the payload type and pointed-to function signature have nothing to do with each other, and GC references to and within the payload should still work properly even if I cast a delegate with N arguments to one with zero. But I'm just guessing here. For context, I'm working on an event system for a small hobby project, and it would be extremely useful if I could store delegates with different type signatures in the same storage container; these delegates will always be converted back to the correct type signature before being called (probably by storing typeinfo of the first / only event argument and comparing that), so that's a non-issue. Using a different approach than putting listeners that can listen to any kind of event everywhere might be better and more efficient architecturally, but would be much less flexible / powerful I think. And yes, I've looked into std.variadic; I just want something slightly lower-level with more control over how I actually dispatch and filter events. Ah, and uh... one last thing. What's the worst that could happen from calling a `ref Foo` signature through a void* pointer? Once again, using delegate / function pointer casting shenanigans. Foo is a struct. The memory layout seems to be the same, so this technically works. Thanks!
Jun 02 2017
On Friday, 2 June 2017 at 21:14:29 UTC, Seiji Emery wrote:[...] assume that they're implemented as a pair of pointers; presumably a C function pointer, and a GC-managed payload / context / this pointer – is this correct?Essentially, yes[1]. Though it's a D function pointer, not C.Secondly, is it safe to typecast delegates for storage purposes – ie. cast `void delegate (ref Foo)` to `void delegate()`, or something similar?It works for me, but if you're asking in terms of spec: I don't think it is specified. Though considering that you have to cast it back to the correct type I wouldn't call it safe.The main worry that I have is that this could somehow wreak havoc with the GC-managed payload pointer, but I'm not sure.AFAIK the GC won't collect any object that it considers live, so as long as you keep the context pointer somewhere the GC considers live, you are safe. See [2] on what the current implementation considers live.For context, I'm working on an event system for a small hobby project, and it would be extremely useful if I could store delegates with different type signatures in the same storage container; [...]Be sure that if you interact with operating system mechanisms such as epoll or kqueue to never have the OS C side point to memory that is not also pointed to from the D side or registered via GC.addRoot / GC.addRange, or you are likely going to end up with C pointers into collected memory.Ah, and uh... one last thing. What's the worst that could happen from calling a `ref Foo` signature through a void* pointer?Undefined behaviour. [1] https://dlang.org/spec/abi.html#delegates [2] https://dlang.org/phobos/core_memory.html#.GC
Jun 02 2017
On Friday, 2 June 2017 at 21:42:57 UTC, Moritz Maxeiner wrote:On Friday, 2 June 2017 at 21:14:29 UTC, Seiji Emery wrote:[...] assume that they're implemented as a pair of pointers;His computer could expode! Or it could trigger a black hole near Alpha Centauri... You never know!Ah, and uh... one last thing. What's the worst that could happen from calling a `ref Foo` signature through a void* pointer?Undefined behaviour.
Jun 03 2017
On Fri, Jun 02, 2017 at 09:14:29PM +0000, Seiji Emery via Digitalmars-d wrote: [...]For context, I'm working on an event system for a small hobby project, and it would be extremely useful if I could store delegates with different type signatures in the same storage container;[...] Adam Ruppe has done this, you can probably find your answers in his code: https://github.com/adamdruppe/arsd/blob/master/eventloop.d especially the parts related to addListener() and wrap(). T -- Once bitten, twice cry...
Jun 02 2017
On 2017-06-02 23:14, Seiji Emery wrote:The main worry that I have is that this could somehow wreak havoc with the GC-managed payload pointer, but I'm not sure.As long as you cast between different type of delegates I don't think it would be a problem. The context pointer is always void* regardless of the signature of the delegate. -- /Jacob Carlborg
Jun 03 2017