Inject fresh variable in scope

  • Thread starter Andrei Alexandrescu (See Website For Email)
  • Start date
A

Andrei Alexandrescu (See Website For Email)

Hello,


I set out to write a useful OnScopeExit feature that's supposed to
execute some code when the current scope is exited. What I came up with is:

package OnScopeExit;
my $todo = sub {};
sub new { shift; $todo = shift; bless {}; }
sub DESTROY {
&$todo;
}
package main;
sub OnScopeExit(&) {
return new OnExit(shift);
}

Now I can say in any scope I please:

{
... code ...
my $tempFile = "/tmp/temp.txt";
my $cookie1 = OnScopeExit { unlink($tempFile); };
... code ...
}

Sure enough, when the current scope exits, the local $cookie1 will have
its reference count go to zero, the DESTROY sub gets called, and the
code that deletes the temporary file is invoked. Very nice.

The only annoying part is that I need to define some "my" variable with
a unique name for each OnScopeExit action I want to perform. Ideally,
I'd only need to write:

{
... code ...
my $tempFile = "/tmp/temp.txt";
OnScopeExit { unlink($tempFile); }
... code ...
}

that is, the creation of a lexically-scoped anonymous variable that will
go out of scope should be somehow automated.

I looked through symbol tables, scratchpads, and the ilk, for a couple
of hours, to no avail. Is there a way?


Thanks,

Andrei
 
A

A. Sinan Unur

I set out to write a useful OnScopeExit feature that's supposed to
execute some code when the current scope is exited.
....

Sure enough, when the current scope exits, the local $cookie1 will
have its reference count go to zero, the DESTROY sub gets called, and
the code that deletes the temporary file is invoked. Very nice.

The only annoying part is that I need to define some "my" variable
with a unique name for each OnScopeExit action I want to perform.

If you are willing to live with the necessity of creating only one
lexically scoped AtExit object, you might find:

http://search.cpan.org/~bradapp/AtExit-2.01/AtExit.pm

useful.

Sinan
 
E

Eric J. Roode

Hello,


I set out to write a useful OnScopeExit feature that's supposed to
execute some code when the current scope is exited. What I came up
with is:

package OnScopeExit;
my $todo = sub {};
sub new { shift; $todo = shift; bless {}; }
sub DESTROY {
&$todo;
}
package main;
sub OnScopeExit(&) {
return new OnExit(shift);
}

Now I can say in any scope I please:

{
... code ...
my $tempFile = "/tmp/temp.txt";
my $cookie1 = OnScopeExit { unlink($tempFile); };
... code ...
}

Sure enough, when the current scope exits, the local $cookie1 will
have its reference count go to zero, the DESTROY sub gets called, and
the code that deletes the temporary file is invoked. Very nice.

The only annoying part is that I need to define some "my" variable
with a unique name for each OnScopeExit action I want to perform.
Ideally, I'd only need to write:

{
... code ...
my $tempFile = "/tmp/temp.txt";
OnScopeExit { unlink($tempFile); }
... code ...
}

that is, the creation of a lexically-scoped anonymous variable that
will go out of scope should be somehow automated.

I looked through symbol tables, scratchpads, and the ilk, for a couple
of hours, to no avail. Is there a way?

I don't believe so. I tried this same sort of thing a while back,
and I couldn't think of any way.

Two things about your object class, above. One, you should not use
a package variable ($todo) to store your action. What if someone needed
to do this?

{
my $one = OnScopeExit {...};
{
my $two = OnScopeExit {...};
}
}

For each object, store the to-do action *in* the object itself.
Instead of:
sub new { shift; $todo = shift; bless {}; }
do
sub new { shift; bless { todo => shift }; }

Second: Don't hardcode OnScopeExit to be in package main. What if
you need an end-of-scope action in a module you're developing, a
module that exists in a different namespace than "main"? Export it
properly, via the Exporter module.

HTH.

--
Eric
`$=`;$_=\%!;($_)=/(.)/;$==++$|;($.,$/,$,,$\,$",$;,$^,$#,$~,$*,$:,@%)=(
$!=~/(.)(.).(.)(.)(.)(.)..(.)(.)(.)..(.)......(.)/,$"),$=++;$.++;$.++;
$_++;$_++;($_,$\,$,)=($~.$"."$;$/$%[$?]$_$\$,$:$%[$?]",$"&$~,$#,);$,++
;$,++;$^|=$";`$_$\$,$/$:$;$~$*$%[$?]$.$~$*${#}$%[$?]$;$\$"$^$~$*.>&$=`
 
B

brianr

Eric J. Roode said:
I don't believe so. I tried this same sort of thing a while back,
and I couldn't think of any way.

Two things about your object class, above. One, you should not use
a package variable ($todo) to store your action. What if someone needed
to do this?

{
my $one = OnScopeExit {...};
{
my $two = OnScopeExit {...};
}
}

For each object, store the to-do action *in* the object itself.
Instead of:
do
sub new { shift; bless { todo => shift }; }

Second: Don't hardcode OnScopeExit to be in package main. What if
you need an end-of-scope action in a module you're developing, a
module that exists in a different namespace than "main"? Export it
properly, via the Exporter module.

ISTM that it could be done with a source filter e.g.

use strict;
use warnings;

package OnScopeExitHelper;

sub new ($&) {
shift;
return bless {code => shift};
}

sub DESTROY {
&{$_[0]->{code}};
}

package UniqueVarName;

require Tie::Scalar;
our @ISA = qw /Tie::StdScalar/;

our $base_var = "aaaaaaaaa";

sub FETCH {
return $base_var++;
}

package OnScopeExit;

use Filter::Simple;
use Regexp::Common qw /balanced/;

our $var;
tie $var, 'UniqueVarName';

FILTER_ONLY code => sub { s{\b OnScopeExit \b
\s+
( $RE{balanced}{-parens=>'{}'} )
}
{my \$$var = OnScopeExitHelper->new(sub $1)
}gsx
};

1;

Seems to work, but I expect that it could be improved.

HTH
 
E

Eric J. Roode

ISTM that it could be done with a source filter

Hmmm, that's not a bad idea. I must explore that.

--
Eric
`$=`;$_=\%!;($_)=/(.)/;$==++$|;($.,$/,$,,$\,$",$;,$^,$#,$~,$*,$:,@%)=(
$!=~/(.)(.).(.)(.)(.)(.)..(.)(.)(.)..(.)......(.)/,$"),$=++;$.++;$.++;
$_++;$_++;($_,$\,$,)=($~.$"."$;$/$%[$?]$_$\$,$:$%[$?]",$"&$~,$#,);$,++
;$,++;$^|=$";`$_$\$,$/$:$;$~$*$%[$?]$.$~$*${#}$%[$?]$;$\$"$^$~$*.>&$=`
 
A

Andrei Alexandrescu (See Website For Email)

ISTM that it could be done with a source filter e.g.

(snip)

Thanks! Interesting idea; I got it to work, but then I noticed someone
has written something along the same lines:

http://search.cpan.org/~abergman/Hook-Scope-0.04/Scope.pm

Now, I tried to install that, and found out it depends on a zillion
other modules. Now, the question is: is there a simple way to manage
dependencies in Perl - i.e., download a package and all of its
dependents from somewhere? Thanks!


Andrei
 
T

Tad McClellan

Andrei Alexandrescu (See Website For Email) said:
Now, the question is: is there a simple way to manage
dependencies in Perl - i.e., download a package and all of its
dependents from somewhere?


perldoc CPAN
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top