SPUG: Coupling of closure parsing and compilation

Yitzchak Scott-Thoennes sthoenna at efn.org
Tue Oct 7 13:30:50 CDT 2003


On Sun, Oct 05, 2003 at 04:22:51PM -0700, Fred Morris <m3047 at inwa.net> wrote:
> I was toying with the notion of using closures for the second part of a
> two-phase execution, but I'm not clear on the performance implications.
> What's going to happen is an object is going to do some setup, then there
> needs to be a handoff to something else, which needs to call back after
> it's done:

It looks to me as if you have some encapsulation problems.  Perhaps
you want a is-a b instead of a has-a b.  Or perhaps you want to get
rid of here_ya_go and have a $a->do_more_stuff that calls
$b->do_more_stuff and $a->finis?  Or perhaps you know you are
violating the encasulation but are trying to do it in a clean and
documented manner.  It's hard to tell when you've abstracted the
example down to just syntax rather than semantics.

>     &{$self->{finis}}();
> 
>     (should I delete $self->{finis} here or am I just superstitious?)

Since $b->{finis} will hold a refcnt on $a, you probably want to clear
it when done with it to get orderly destruction.  Or something like this
ought to work:

    weaken(my $weak_self=$self));
    $self->{b}->here_ya_go(
       sub { defined($weak_self) or return; $weak_self->finis(); }
    );

> What I can't quite get clear in my mind is the coupling between the parsing
> of the Perl source and when the substitutions actually occur which produce
> the closure, and what effect this would have on performance both in terms
> of cpu and memory; the closures won't be particularly large chunks of code
> (although they'll call fairly large chunks of code). But they will be
> (re)created often.
> 
> Is the source for the closure parsed with the rest of the chunk, or at the
> time that the closure is instantiated?
> 
> Is the instantiated closure produced by (cloning if necessary, and then)
> substituting into the (parsed) opcode tree?
> 
> What's the overhead of using a closure once and then throwing it away?

In simple (hence inaccurate) terms, a coderef has two parts, the
optree and the pad.  The binding that makes it a closure lives in the
pad and is generated at run-time when you hit the sub {} statement.
The optree, OTOH, is generated from the sub {} body at compile-time.
The overhead is low.

> Am I just asking for circular memory references here, given the OO "have
> you call me" scenario (bear in mind, the object(s) creating the closures
> won't be keeping handles to them, but they will be referencing themselves
> within the closures).

Yes, but see above.

> Experience only, please. Pursuit of elegance is great, if it has a high
> expectation of success.

Whoops.  Ignore my first few elegance-pursuing sentences.



More information about the spug-list mailing list