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.

Reply via email to