I implemented delegates in D
maik klein via Digitalmars-d
digitalmars-d at puremagic.com
Sat Jun 11 04:29:52 PDT 2016
On Thursday, 9 June 2016 at 23:53:33 UTC, BBasile wrote:
> On Thursday, 9 June 2016 at 21:02:26 UTC, maik klein wrote:
>> I am currently writing a task system and I have this case
>> where I want to send a delegate to a different thread but this
>> delegate also captures a variable. I use this to implement a
>> "future".
>>
>> Now as far as I know this delegate will allocate GC memory and
>> I just wanted to avoid that, just for fun.
>>
>> Here is the code https://dpaste.dzfl.pl/cd77fce99a5b
>>
>> I have only worked on it a couple of hours and I am sure there
>> are many problems with it.
>>
>> Basically the idea is that you can use normal lambda syntax.
>> If you want a function that returns and int and takes an int,
>> you can write it like this:
>>
>> (int i) => i
>>
>> If you want a function that returns an int, takes an int, but
>> also captures and int you would write it like this
>>
>> (int i, int captured) => i + captured
>>
>> But you also have to declare the base function type without
>> the captured variables beforehand.
>>
>> Fn!(FnType!(int, int), (int i, int captured) => i +
>> captured)(42);
>>
>> That is how I know what the captured variables are.
>>
>> The only part that is currently missing are polymorphic
>> delegates. They are not too useful if I can't pack them into
>> the same array.
>>
>> I guess I have to do this with classes/interfaces.
>>
>> Thoughts?
>>
>> Has this been done before?
>
> What you have here is more functor, to the extent that you can
> memorize the parameters. The problem is that it's not
> compatible with the delegates as defined in the language.
>
> Actual D delegates get collected when we take the address and
> the context of a member function with "&". To allocate the
> delegate itself in the non GC heap is easy (with a struct that
> contains two pointers).
>
> Your message has motivated me to make this, thanks to a union
> true nogc delegates are possible:
>
> =========================================
> module runnable;
>
> union Delegate(FT)
> {
> // delegate layout as defined in the D ABI
> struct DgMembers
> {
> void* ptr;
> FT funcptr;
> }
> DgMembers members;
>
> // the 2nd member is "true" D delegate type
> import std.array: replace;
> mixin("alias DT = " ~ FT.stringof.replace("function",
> "delegate") ~ ";");
> DT dg;
> }
>
> void main() @nogc
> {
> static struct Foo
> {
> @nogc string delegate() test;
> @nogc string source() {return "test";}
> }
>
> import std.experimental.allocator.mallocator;
> import std.experimental.allocator;
>
> Foo foo;
> alias DelegateT = Delegate!(typeof(&Foo.source));
>
> // &Foo.source takes the static address, i.e in the data
> segment
> DelegateT* dg = make!DelegateT(Mallocator.instance);
> dg.members.ptr = &foo;
> dg.members.funcptr = &Foo.source;
>
> foo.test = dg.dg;
> assert(foo.test() == "test");
> }
> =========================================
>
> Here you have a true D delegate that's conform with the
> language.
The problem is I currently do this
struct LocalTaskQueue{
...
Array!(Box!Fiber) work;
Array!(Box!Fiber) queuedWork;
...
}
This is where I submit my delegates to, but before that I also
wrap them inside a fiber. Btw "Box" is my version of Unique.
I execute a fiber inside work and if it is done I want to delete
it, because it is not needed anymore. If it is on hold it
transfer it from "work" to queuedWork.
That means I need be able to put my delegates inside a fiber,
this is the constructor for a Fiber currently.
this( void delegate() dg, size_t sz = PAGESIZE*4 ) nothrow
in
{
assert( dg );
}
body
{
allocStack( sz );
reset( dg );
}
I mean I can easily convert my "Fn" version to delegate with
&foo.opCall, but then I would not know how long my "Fn" should
stay alive.
I think what I can do is switch my struct Fn to a class and
implement my own function polymorphism.
I would then do
Array!(Box!Fiber) work;
Array!(Box!PolymorphicFn!(void, void)) rawFunction;
and when I delete a fiber from work I can delete it from
rawFunction.
But that seems to be so much trouble just to avoid a bit of GC.
More information about the Digitalmars-d
mailing list