FunctionalPerl
view release on metacpan or search on metacpan
lib/FP/Weak.pm view on Meta::CPAN
#
# Copyright (c) 2015-2020 Christian Jaeger, copying@christianjaeger.ch
#
# This is free software, offered under either the same terms as perl 5
# or the terms of the Artistic License version 2 or the terms of the
# MIT License (Expat version). See the file COPYING.md that came
# bundled with this file.
#
=head1 NAME
FP::Weak - utilities to weaken references
=head1 SYNOPSIS
use FP::Weak;
sub foo {
my $f; $f = sub { my ($n,$tot) = @_; $n < 100 ? &$f($n+1, $tot+$n) : $tot };
Weakened $f
}
is foo->(10, 0), 4905;
# the subroutine returned from foo will not be leaked.
=head1 DESCRIPTION
=over 4
=item weaken <location>
`Scalar::Util`'s `weaken`, unless one of the `with_..` development
utils are used (or `$FP::Weak::weaken` is changed).
=item Weakened <location>
Calls `weaken <location>` after copying the reference, then returns
the unweakened reference.
=item Keep <location>
Protect <location> from being weakened by accessing elements of `@_`.
=back
Optionally exported development utils:
=over 4
=item noweaken ($var), noWeakened ($var)
No-ops. The idea is to prefix the weakening ops with 'no' to disable
them.
=item warnweaken ($var), warnWeakened ($var)
Give a warning in addition to the weakening operation.
=item cluckweaken ($var), cluckWeakened ($var)
Give a warning with backtrace in addition to the weakening operation.
=item with_noweaken { code }, &with_noweaken ($proc)
=item with_warnweaken { code } (and same as above)
=item with_cluckweaken { code }
Within their dynamic scope, globally change `weaken` to one of the
alternatives
=item do_weaken (1|0|"yes"|"no"|"on"|"off"|"warn"|"cluck")
Turn weakening on and off (unscoped, 'persistently').
=back
=head1 NOTE
This is alpha software! Read the status section in the package README
or on the L<website|http://functional-perl.org/>.
=cut
package FP::Weak;
use strict;
use warnings;
use warnings FATAL => 'uninitialized';
use Exporter "import";
our @EXPORT = qw(weaken Weakened Keep);
our @EXPORT_OK = qw(
do_weaken
noweaken noWeakened with_noweaken
warnweaken warnWeakened with_warnweaken
cluckweaken cluckWeakened with_cluckweaken
);
our %EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]);
use Scalar::Util ();
use FP::Carp;
our $weaken = \&Scalar::Util::weaken;
sub weaken {
@_ == 1 or fp_croak_arity 1;
goto &$weaken
}
# XX is there really no way (short of re-exporting everywhere with a
# Chj::ruse approach) to avoid the extra function call cost?
# protect a variable from being pruned by callees that prune their
# arguments
sub Keep {
@_ == 1 or fp_croak_arity 1;
my ($v) = @_;
$v
}
# weaken a variable, but also provide a non-weakened reference to its
# value as result
sub Weakened {
@_ == 1 or fp_croak_arity 1;
my ($ref) = @_;
weaken $_[0];
$ref
}
sub noweaken {
@_ == 1 or fp_croak_arity 1;
# noop
}
sub noWeakened {
@_ == 1 or fp_croak_arity 1;
$_[0]
}
sub with_noweaken (&) { local $weaken = \&noweaken; &{ $_[0] }() }
use Carp;
sub warnweaken {
@_ == 1 or fp_croak_arity 1;
carp "weaken ($_[0])";
Scalar::Util::weaken($_[0]);
}
sub warnWeakened {
@_ == 1 or fp_croak_arity 1;
carp "weaken ($_[0])";
Weakened($_[0]);
}
sub with_warnweaken (&) { local $weaken = \&warnweaken; &{ $_[0] }() }
use Carp 'cluck';
use FP::Carp;
sub cluckweaken {
@_ == 1 or fp_croak_arity 1;
cluck "weaken ($_[0])";
Scalar::Util::weaken($_[0]);
}
sub cluckWeakened {
@_ == 1 or fp_croak_arity 1;
cluck "weaken ($_[0])";
Weakened($_[0]);
}
sub with_cluckweaken (&) { local $weaken = \&cluckweaken; &{ $_[0] }() }
sub do_weaken {
@_ == 1 or fp_croak_arity 1;
my ($v) = @_;
my $w = $v
? (
+{
1 => \&Scalar::Util::weaken,
"yes" => \&Scalar::Util::weaken,
"no" => \&noweaken,
"on" => \&Scalar::Util::weaken,
"off" => \&noweaken,
"noweaken" => \&noweaken,
"warn" => \&warnweaken,
"warnweaken" => \&warnweaken,
"cluck" => \&cluckweaken,
"cluckweaken" => \&cluckweaken,
}->{$v} // die "do_weaken: unknown key '$v'"
)
: \&noweaken;
$weaken = $w
}
1
( run in 0.746 second using v1.01-cache-2.11-cpan-39bf76dae61 )