develooper Front page | perl.perl5.porters | Postings from May 2015

Re: Premature freeing with "Non-eval closures don't need CvOUTSIDE"

Thread Previous | Thread Next
From:
Christian Jaeger
Date:
May 6, 2015 16:04
Subject:
Re: Premature freeing with "Non-eval closures don't need CvOUTSIDE"
Message ID:
CAEjYwfWwda_Hmn=q3--depDQAG44OoMUcSWf761ZXByM=N+Nog@mail.gmail.com
I'm realizing that I was thinking wrongly about the "visibility" as a
reason for retention here; even if the inner closure referencing $f is
retained, it will let go of the value in $f as $f is weak.

So, I was relying on a Perl bug in the past. And was corrupting my thinking
to fit its behaviour.

On the plus side, it's amazing that Perl is really getting increasingly
bug-free lately.

On the negative side, this means I need to find another solution.

Also, I'll really have to add a precise guide and explanation to the
"functional-perl" docs about how Perl works with regards to reference
maintenance. (Well, it just got one bit easier to explain now with that
recent change; but there's a lot to know now still (*and* it should mention
older Perls too).) Does such a document exist already or should I start one?

It should cover:

(1) the "obvious"/widely documented things:
- mutation can lead to reference cycles, those are not collected
- explicit undef, perhaps with destructors, and "weaken" as solutions

(2) the non-obvious things:
- while being interpreted, a reference to a closure is being retained even
if no variable is holding a strong reference anymore (which is the case
when using goto $last_strong_variable).
- in newer perls, closures don't retain references to lexicals in their
environment anymore if their bodies don't contain any reference.
- assignment to @_ (@_= ..): clears it out, but doesn't change the
variables in the caller
- assignment to $_[..]: change variables in the caller; but what about when
the argument was not a variable reference?
- the best ways to debug memory problems
- the best ways to write tests to detect leaking behaviour (memory limits,
or measurements, using BSD::Resource, or what?)

(0) Wording:
- ambiguity with: "to reference" (access a variable), vs. "a reference"
(lowlevel, my $a=$b; creating a new one) vs. "a reference" (perl-level
reference, my $a=$b; just creating a new lowlevel reference for the same
high-level one)  (Sentences like my "a variable is holding a strong
reference" above are very unclear without context.)
- variable vs. binding vs. slot vs. lexical pad vs. ..

Perhaps more.


2015-05-06 10:06 GMT+01:00 Leon Timmermans <fawaka@gmail.com>:

> The usual approach is to keep a strong reference around that isn't closed
> over.
>

Yes, this solves it:

sub foo {
    my $f; $f= sub {
        my ($n)= @_;
        my $f=$f; # create a new, strong binding for f to prevent it
                  # from being freed (upon return from f)
        sub {
            if ($n > 0) {
                $n + &{&$f($n - 1)}

(
https://github.com/pflanze/functional-perl/blob/master/t/perl/weaken-coderef-simplified
)



> Another way to achieve what you want to achieve without closure circular
> references is to pass $f a reference to itself as an argument, Y-combinator
> style.
>

This is worse than the actual Y combinator in that this way also callers of
the function have to remember to pass the function as an argument to
itself. To be fair, the above is now complex enough that maybe using the Y
combinator instead is actually a good idea; I'll have to play more with it
and see what other people think. (Perl's subroutines are also slow enough
that the Y combinator poses a problematic amount of overhead. I'm aware
that your suggestion saves most of that.)

Thanks,
Christian.

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About