Named nested subroutines?

R

Rainer Weikusat

Are the other gotchas with named nested subroutines than the 'variable
will not stay shared' issue?
 
J

John W. Krahn

Rainer said:
Are the other gotchas with named nested subroutines than the 'variable
will not stay shared' issue?

Named subroutines cannot be "nested" because their names are package
variables and so do not follow lexical scoping rules.

The problem you are having is with lexical variables that are in the
wrong scope.



John
 
R

Rainer Weikusat

John W. Krahn said:
Named subroutines cannot be "nested" because their names are package
variables and so do not follow lexical scoping rules.

To a degree, they can

----------
#!/usr/bin/perl

sub blubb
{
return 'blubb';
}

sub blah
{
local *blubb = sub { return 'yadda'; };
return blubb();
}

print blubb(), " ", blah(), "\n";
----------

but I was asking about named subroutines defined
inside other named subroutines, eg

sub a
{
sub b { return 1; }
return 2;
}

specifically, because I'm using PL/Perl (Perl as PostgreSQL
procedural language) for a task which isn't entirely trivial anymore
and I would like to avoid having to put all my helper subs as
anonymous subroutines into %_SHARED and invoking them by going through
this hash. The PL/Perl documentation recommends against this,
calling it 'dangerous' and referring to perldiag for details. But the
only thing this manpage has to say to that is the 'variable will
not stay shared' issue[*] which doesn't affect me because I need to
put definitions of named subroutines into an anonymous Perl
subroutine (PL/Perl top-level construct) but all I want is creating
functions with ordinary names which can be invoked as usual.

[*] Not that this would really be true (tested with 5.10.1,
known to be working for some older version as well):

----------------
sub howl
{
my $x;

$x = 2;

{
sub yodel { return $x; }
}

return sub { ++$x; };
}

my $inc = howl();

print yodel, "\n";
$inc->();
print yodel, "\n";
$inc->();
print yodel, "\n";
-----------------

[rw@sapphire]/tmp $perl -w a.pl
Variable "$x" will not stay shared at a.pl line 9.
2
3
4
 
R

Rainer Weikusat

Ben Morrow said:
[...]
sub howl
{
my $x;

$x = 2;

{
sub yodel { return $x; }
}

return sub { ++$x; };
}

my $inc = howl();

print yodel, "\n";
$inc->();
print yodel, "\n";
$inc->();
print yodel, "\n";

my $again = howl();
say(yodel), $again->() for 1..3;

You only called &howl once, so there was only ever one copy of $x and
therefore no problem. The problem arises when you call it again, so
there are now two copies of $x, so it's no longer clear which copy the
global &yodel should refer to.

Unless it is redefined (which it isn't), it should continue to refer to the same $x it
originally referred to. After all, the closure created by a 2nd
invocation also won't "share" an $x with the closure created by the
first one. But I certainly misunderstood the warning ...
 
R

Rainer Weikusat

[...]
The subs are actually defined at (Perl) compile time, so depending on
exactly when Pg passes the string to perl to be compiled you may find
you don't need to *run* setup_subs() at all, just CREATE it. You may
also find this is unpredictable and depends on exactly which perl
instance you end up with each time; I don't know the details of when Pg
passes which functions to which Perl instances, but it may be that if
you haven't run setup_subs() in this session this Perl interpreter won't
have seen the definition at all.

For 'interpreted' procedural language routines, it just stores the
source code in the pg_proc table and passes it to the Perl
interpreter associated with the current session (for Linux/UNIX(*)),
this means 'the process handling the client connection') either when
the subroutine needs to be executed for the first time or after the
defining command was encountered.
[Being an evil-minded person, it occurs to me at this point to wonder
what happens if you say

CREATE FUNCTION setup_subs() RETURNS void AS $$
};

sub foo { ... }
sub bar { ... }

sub {
$$ LANGUAGE plperl;

Little Bobby Tables, and so on...]

The source code is really just wrapped into sub { }, cf

[rw@splittermine]/tmp $sudo -u postgres psql -U postgres -d mad_database
psql (8.4.8)
Type "help" for help.

mad_database=# create or replace function pltest() returns integer as $$ }; sub aaa { return 12; } sub { return aaa(); $$ language plperlu;
CREATE FUNCTION
mad_database=# select pltest();
pltest
--------
12
(1 row)
mad_database=# \q
[rw@splittermine]/tmp $sudo -u postgres psql -U postgres -d mad_database
psql (8.4.8)
Type "help" for help.

mad_database=# create or replace function pltest2() returns integer as $$ return aaa(); $$ language plperlu;
CREATE FUNCTION
mad_database=# select pltest2();
ERROR: error from Perl function "pltest2": Undefined subroutine &main::aaa called at line 1.
mad_database=# select pltest();
pltest
--------
12
(1 row)

mad_database=# select pltest2();
pltest2
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top