www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Manually allocate delegate?

reply "Tofu Ninja" <emmons0 purdue.edu> writes:
Is it even possible?
Jul 12 2015
next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 12 Jul 2015 08:38:00 +0000, Tofu Ninja wrote:

 Is it even possible?
what do you mean?=
Jul 12 2015
parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
On Sunday, 12 July 2015 at 08:47:37 UTC, ketmar wrote:
 On Sun, 12 Jul 2015 08:38:00 +0000, Tofu Ninja wrote:

 Is it even possible?
what do you mean?
Sorry, thought the title was enough. The context for a delegate(assuming not a method delegate) is allocated by the GC. Is there any way to allocate the context manually.
Jul 12 2015
next sibling parent reply "Baz" <bb.temp gmx.com> writes:
On Sunday, 12 July 2015 at 09:03:25 UTC, Tofu Ninja wrote:
 On Sunday, 12 July 2015 at 08:47:37 UTC, ketmar wrote:
 On Sun, 12 Jul 2015 08:38:00 +0000, Tofu Ninja wrote:

 Is it even possible?
what do you mean?
Sorry, thought the title was enough. The context for a delegate(assuming not a method delegate) is allocated by the GC. Is there any way to allocate the context manually.
You can copy a delegate in a GC-free chunk but so far i think that the simple fact to get a delegate with "&" will allocate from the GC. By the way i'd be interested to see the runtime function that creates a delegate. i see nothing in druntime. --- import std.stdio, std.c.stdlib, std.c.string; class Foo { void bar(){writeln("bang");} } void main(string[] args) { auto foo = new Foo; auto dg0 = &foo.bar; auto dg1 = *cast(void delegate()*) malloc(size_t.sizeof * 2); memmove(cast(void*)&dg1, cast(void*)&dg0, size_t.sizeof * 2); dg1(); } ---
Jul 12 2015
parent reply "Tofu Ninja" <emmons0 purdue.edu> writes:
On Sunday, 12 July 2015 at 10:19:02 UTC, Baz wrote:
 You can copy a delegate in a GC-free chunk but so far i think 
 that the simple fact to get a delegate with "&" will allocate 
 from the GC.

 By the way i'd be interested to see the runtime function that 
 creates a delegate.
 i see nothing in druntime.

 ---
 import std.stdio, std.c.stdlib, std.c.string;

 class Foo {
     void bar(){writeln("bang");}
 }

 void main(string[] args) {
     auto foo = new Foo;
     auto dg0 = &foo.bar;
     auto dg1 = *cast(void delegate()*) malloc(size_t.sizeof * 
 2);
     memmove(cast(void*)&dg1, cast(void*)&dg0, size_t.sizeof * 
 2);
     dg1();
 }
 ---
That is not manually allocating a delegate context, and & in that instance does not even allocate. For delegates to class methods, the context is just the "this" pointer of the object, so the context in that code is just foo, which you still allocated on the gc. The delegate itself (the function pointer and the context pointer) is just allocated on the stack. What I am talking about is the context that implicitly gets allocated when you make a delegate to a nested function. void main(string[] args) { auto d = bar(); d(); } auto bar() { int x = 5; void foo() { writeln(x); } auto d = &foo; // <-- allocates return d; }
Jul 12 2015
parent reply "Baz" <bb.temp gmx.com> writes:
On Sunday, 12 July 2015 at 10:39:44 UTC, Tofu Ninja wrote:
 On Sunday, 12 July 2015 at 10:19:02 UTC, Baz wrote:
 [...]
That is not manually allocating a delegate context, and & in that instance does not even allocate. For delegates to class methods, the context is just the "this" pointer of the object, so the context in that code is just foo, which you still allocated on the gc. The delegate itself (the function pointer and the context pointer) is just allocated on the stack. What I am talking about is the context that implicitly gets allocated when you make a delegate to a nested function. void main(string[] args) { auto d = bar(); d(); } auto bar() { int x = 5; void foo() { writeln(x); } auto d = &foo; // <-- allocates return d; }
At least now your Question is clearer and understandable...but sorry goodbye. I don't feel good vibes here. See ya ^^.
Jul 12 2015
parent "Tofu Ninja" <emmons0 purdue.edu> writes:
On Sunday, 12 July 2015 at 11:22:41 UTC, Baz wrote:
 At least now your Question is clearer and understandable...but 
 sorry goodbye. I don't feel good vibes here. See ya ^^.
Sorry if I came off as rude, didn't mean to... >.>
Jul 12 2015
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 12 Jul 2015 09:03:24 +0000, Tofu Ninja wrote:

 On Sunday, 12 July 2015 at 08:47:37 UTC, ketmar wrote:
 On Sun, 12 Jul 2015 08:38:00 +0000, Tofu Ninja wrote:

 Is it even possible?
what do you mean?
=20 Sorry, thought the title was enough. =20 The context for a delegate(assuming not a method delegate) is allocated by the GC. Is there any way to allocate the context manually.
nope. there is no way to overload context allocation function, afaik. at=20 least without patching druntime, and i still don't know what one have to=20 patch. ;-)=
Jul 12 2015
next sibling parent "Tofu Ninja" <emmons0 purdue.edu> writes:
On Sunday, 12 July 2015 at 11:42:09 UTC, ketmar wrote:
 On Sun, 12 Jul 2015 09:03:24 +0000, Tofu Ninja wrote:

 On Sunday, 12 July 2015 at 08:47:37 UTC, ketmar wrote:
 On Sun, 12 Jul 2015 08:38:00 +0000, Tofu Ninja wrote:

 Is it even possible?
what do you mean?
Sorry, thought the title was enough. The context for a delegate(assuming not a method delegate) is allocated by the GC. Is there any way to allocate the context manually.
nope. there is no way to overload context allocation function, afaik. at least without patching druntime, and i still don't know what one have to patch. ;-)
Hmmmmm.... with allocators being added, this seems like something that needs to be fixed. Maybe when allocators do get added then the implicit allocations for the context could be done with the global allocator, that and other implicit allocations like array resizing. Guess I will just wait and see how it plays out.
Jul 12 2015
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 12 July 2015 at 11:42:09 UTC, ketmar wrote:
 nope. there is no way to overload context allocation function, 
 afaik. at least without patching druntime, and i still don't 
 know what one have to patch. ;-)
_d_allocmemory
Jul 12 2015
parent ketmar <ketmar ketmar.no-ip.org> writes:
On Sun, 12 Jul 2015 12:45:10 +0000, Adam D. Ruppe wrote:

 On Sunday, 12 July 2015 at 11:42:09 UTC, ketmar wrote:
 nope. there is no way to overload context allocation function,
 afaik. at least without patching druntime, and i still don't know what
 one have to patch. ;-)
=20 _d_allocmemory
tnx. if i note that i don't know which function does something, there=20 always be someone who will point me at the function. like it! ;-)=
Jul 13 2015
prev sibling parent reply userABCabc123 <userABCabc123 ab.ab.ba> writes:
On Sunday, 12 July 2015 at 09:03:25 UTC, Tofu Ninja wrote:
 On Sunday, 12 July 2015 at 08:47:37 UTC, ketmar wrote:
 On Sun, 12 Jul 2015 08:38:00 +0000, Tofu Ninja wrote:

 Is it even possible?
what do you mean?
Sorry, thought the title was enough. The context for a delegate(assuming not a method delegate) is allocated by the GC. Is there any way to allocate the context manually.
Yes: ======================== class Foo { void bar(){writeln(__PRETTY_FUNCTION__);} } auto uncollectedDelegate(T, string name)(ref T t) { import std.experimental.allocator.mallocator; struct Dg{void* ptr, funcptr;} void* funcptr = &__traits(getMember, T, name); void* ptr = cast(void*)t; Dg* dg = cast(Dg*) Mallocator.instance.allocate(Dg.sizeof); dg.ptr = ptr; dg.funcptr = funcptr; return dg; } void main(string[] args) { Foo foo = new Foo; auto dg = uncollectedDelegate!(Foo, "bar")(foo); auto tdg = cast(void delegate()*) dg; (*tdg)(); } ======================== with just a type __traits(getMember,...) on a delegate will only return the function address in the process image. so without the context ptr, just like a static or a global function. Later you set the context by hand, using a pointer to an instance.
Nov 20 2015
parent Tofu Ninja <emmons0 purdue.edu> writes:
On Saturday, 21 November 2015 at 00:30:45 UTC, userABCabc123 
wrote:
 
 Yes:

 ========================
 class Foo
 {
     void bar(){writeln(__PRETTY_FUNCTION__);}
 }

 auto uncollectedDelegate(T, string name)(ref T t)
 {
     import std.experimental.allocator.mallocator;
     struct Dg{void* ptr, funcptr;}

     void* funcptr = &__traits(getMember, T, name);
     void* ptr = cast(void*)t;

     Dg* dg = cast(Dg*) Mallocator.instance.allocate(Dg.sizeof);
     dg.ptr = ptr;
     dg.funcptr = funcptr;
     return dg;
 }

 void main(string[] args)
 {
     Foo foo = new Foo;
     auto dg = uncollectedDelegate!(Foo, "bar")(foo);
     auto tdg = cast(void delegate()*) dg;
     (*tdg)();
 }
 ========================

 with just a type __traits(getMember,...) on a delegate will 
 only return the function address in the process image. so 
 without the context ptr, just like a static or a global 
 function. Later you set the context by hand, using a pointer to 
 an instance.
I think you are misunderstanding a bit what my original question was. The delegate it self is not gc allocated. The delegate it self is just 2 pointers(a function pointer and a context pointer), they are simply stack allocated. I am not woried about allocating that bit. What I am worried about allocating is the context, and primarily the context for nested functions(often called a closure). For delegates to member functions, the context pointer is always just a pointer to the object that you pulled the delegate off of. To avoid gc allocating the context there, all you need to do is just don't gc allocate the object. Simple. In your example the context is still gc allocated with new Foo;. You actually added in another allocation on top of that with the mallocator. You now allocate the delegate it self, which normally can just be stack allocated. The problem that I was concerned about was the case of nested function delegates. For delegates to nested functions that need to generate a closure, the allocation of the closure is implicitly done and done with the gc. As far as I can tell, there is no way to know anything about that closure, not its size, layout, contents, no way to manually allocate it. Example: auto foo(int x) { int bar(){ return x; } return &bar; // <-- implicitly allocates a closure with the gc }
Nov 21 2015
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Sunday, 12 July 2015 at 08:38:01 UTC, Tofu Ninja wrote:
 Is it even possible?
Yes, though you need to use an entirely different approach for closures: make a struct. Remember that delegates can come from local variable use or a `this` object being used and work the same way to the outside world. If it is local variables, the compiler emits the allocate calls and you have little control over it. If it comes from an object though, you have much more control: control over what is stored and control over how it is allocated. The one notable thing you do NOT control is the delegate's lifetime. Once it becomes a delegate, it is interchangable with other delegates and is likely to be mixed in with other things and the recipient has no way of knowing where it came from. That's a feature in general, but it also means they can't know if they have to free() or release_reference() it.... if you need that, you might use a custom delegate type instead of the built in one. Anyway though, just make a struct with the data you need to capture and a call method, then pass that around. Before: void foo() { int a; a = 10; // other code using a use_delegate( { a++; } ); } After: void foo() { static struct Captures { int a; void dg1() { a++; } } Captures captures; with(captures) { a = 10; // other code uing a } use_delegate(&captures.dg1); // WARNING: since captures is owned by this scope, use_delegate had better not hold on to it! But you could just as well have done Captures* captures = malloc(...) too. } So it is slightly more verbose and moves the inline delegate up to the struct (though if you got clever, you could probably change that too, like a delegate factory that takes a function and a this at the call point: dg( (_this) { _this.a++; }, captures); perhaps), but really the extra syntax overhead is small for real programs anyway. And the clarity of what is and isn't captured might be worth it.
Jul 12 2015
parent "Tofu Ninja" <emmons0 purdue.edu> writes:
On Sunday, 12 July 2015 at 12:56:17 UTC, Adam D. Ruppe wrote:
 On Sunday, 12 July 2015 at 08:38:01 UTC, Tofu Ninja wrote:
 Is it even possible?
Yes, though you need to use an entirely different approach for closures: make a struct. [...]
This seems like a reasonable solution, even though it's not perfect, it seems like the only valid way to do this. Tnx :)
Jul 13 2015
prev sibling parent Jack Applegame <japplegame gmail.com> writes:
On Sunday, 12 July 2015 at 08:38:01 UTC, Tofu Ninja wrote:
 Is it even possible?
You can use function instead delegate, and bind captured variables as struct: http://dpaste.dzfl.pl/6e23bbcfe17f auto bind(F: R function(ARGS), R, ARGS...)(F fn, ARGS args) nogc { struct Functor { F fn; ARGS args; this(F fn_, ARGS args_) { fn = fn_; args = args_; } R opCall() { return fn(args); } } return Functor(fn, args); } import std.stdio; auto foo(int x) { static int bar(ref int x){ return x++; } return bind(&bar, x); } void main() { auto f1 = foo(5); auto f2 = foo(10); writefln("%s, %s, %s", f1(), f1(), f1()); writefln("%s, %s, %s", f2(), f2(), f2()); }
Nov 21 2015