Dynamic closure vs static closure
Yigal Chripun
yigal100 at gmail.com
Sat Oct 25 06:30:30 PDT 2008
I probably don't understand something here, but why does the delegate
itself need to know anything about allocation?
see my comments in the body of your message.
KennyTM~ wrote:
>
> OK. Then both the call site and the function need the "scope", since the
> function signature alone is surely insufficient to determine if the
> delegate is closure or not.
>
> Since filling the parameter is just a cloning process, this can be
> reduced to asking if
>
> <delegate-type> f = g;
>
> will produce something weird, when one side is a closure, etc.
>
> The simple solution is to make the delegates on stack a super type of
> delegates on heap.
>
> (Don't mind the "static" keyword yet. I followed the name "static
> closure" described somewhere else. I agree "static" is too overloaded.)
>
>
>
> --------
>
> alias float delegate(in float) FloatDelegate;
>
> // by default delegates are on heap for access safety.
> FloatDelegate g, sin_pi;
>
> // but I can declare it only needs to live on stack.
> // i.e. the parameters won't jump out of its scope.
> static(FloatDelegate) h;
change the above to:
scope FloatDelegate h; // note: *same* type for dg
>
> // require allocation on heap. (right? right?)
> void store (FloatDelegate f) {
> .g = f;
> }
>
the above will heap allocate.
> // don't require to allocation on heap
> float evaluate_at (static(FloatDelegate) f, in float x) {
> return f(x);
> }
float evaluate_at (FloatDelegate f, in float x) {
return f(x);
}
>
> // don't just deal with parameters... the return values need to be
> considered as well.
> FloatDelegate square (FloatDelegate f) {
> return float delegate(in float x) { return f(x)*f(x); }
> }
ok. you'll get heap alloc.
> FloatDelegate plus_zero_of (static(FloatDelegate) f) {
> auto at_zero = f(0);
> return float delegate(in float x) { return x + at_zero; };
> }
FloatDelegate plus_zero_of (scope FloatDelegate f) {
auto at_zero = f(0);
return float delegate(in float x) { return x + at_zero; };
}
> static(FloatDelegate) get_zero_function () {
> return static float delegate(in float) { return 0; };
> }
the above seems wrong to me. it's the same as returning scope class
instances..just define:
FloatDelegate get_zero_function () {
return float delegate(in float) { return 0; };
}
and use:
scope dg1 = get_zero_function(); // this'll prevent heap alloc
>
>
> {
> float pi = 3.1415926535f;
> // don't require allocation on heap.
> // I know this, therefore the static in front.
> auto cos_pi = static float delegate(in float y){ return cos(pi * y); };
> auto tan_pi = static float delegate(in float y){ return tan(pi * y); };
rewrite as:
auto cos_pi = scope float delegate(in float y){ return cos(pi * y); };
auto tan_pi = scope float delegate(in float y){ return tan(pi * y); };
>
> // delegate on stack set to another delegate on stack: OK.
> writefln(evaluate_at(tan_pi, 0.2f));
doesn't matter what "kind" of delegate tan_pi is.
>
> // require allocation on heap
> sin_pi = float delegate(float y) { return sin(pi * y); }
>
> // Oops, cos_pi is on stack, but the func sig requires on heap.
> // should generate error.
> //store(cos_pi);
either error because you assign a scope object to non-scope or perhaps
better alternatives:
a. you use:
store(cos_pi.dup); // manually alloc on heap
b. not an error. *compiler* automatically allocates a copy on heap.
> }
>
> // sin_pi already on heap, although the func sig said can be on stack.
> // should _not_ generate error.
> writefln(evaluate_at(sin_pi, 0.4f));
>
> // g can now stay on stack, although its type is a closure.
> g = get_zero_function();
>
> // also ok.
> h = get_zero_function();
>
> // this should fail.
> h = g;
anyway, I think you got my intention by now.
I really don't want to have 3 kinds of function types. I think the
already exsisting separation between function pointers and delegates
could be handled better by adding an implicit cast.
More information about the Digitalmars-d
mailing list