variables that won't stay shared

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
I have a big glob of data that I'm extracting from a database using
selectall_hashref(). I'm using the primary key to manipulate the data
but I have to print out the data sorted by date, not the primary key.
Here's the relevant portion of the code:

sub output
 foreach my $key (sort bydate keys %)
      print qq($calendarhash-> $calendarhash->
$calendarhash->   $calendarhash->
  $calendarhash-> \n);
      sub bydate
         my  $date_a = $calendarhash->;
         my $date_b = $calendarhash->;
         return $date_a cmp $date_b;

Here's the error message using diagnostics:

$ perl -cw console
Variable "$calendarhash" will not stay shared at line 191
    (W closure) An inner (nested) named subroutine is referencing a
    lexical variable defined in an outer subroutine.

    When the inner subroutine is called, it will probably see the
value of
    the outer subroutine's variable as it was before and during the
    call to the outer subroutine; in this case, after the first call
to the
    outer subroutine is complete, the inner and outer subroutines will
    longer share a common value for the variable.  In other words, the
    variable will no longer be shared.

    Furthermore, if the outer subroutine is anonymous and references a
    lexical variable outside itself, then the outer and inner
    will never share the given variable.

    This problem can usually be solved by making the inner subroutine
    anonymous, using the sub {} syntax.  When inner anonymous subs
    reference variables in outer subroutines are called or referenced,
    are automatically rebound to the current values of such variables.

[Mon Mar  2 13:58:38 2009] Variable "$calendarhash" will
not stay shared at line 191.
Variable "$calendarhash" will not stay shared at line 209 (#1)
[Mon Mar  2 13:58:38 2009] Variable "$calendarhash" will not
stay shared at line 209.
console syntax OK

I want to place the bydate() function WITHIN the lexical scope of the
display function, and can't understand why Perl complains. (Actually,
I can understand why Perl complains, I just can't understand why it
SHOULD complain.)

Is this error message significant? If so, should I remove the bydate()
function from the scope of the display function? I don't care to use
an anonymous function as I feel that it needlessly obscures the code,
and I want to keep the sorting function in the main function for the
same reason.

Thanks, CC.

Re: variables that won't stay shared

Quoted text here. Click to load it
Quoted text here. Click to load it
Quoted text here. Click to load it

You should never place a named sub anywhere that will execute more than
once, whether this is inside another sub or in a loop at the top level.
If you find yourself doing this, you should probably be using an anon
sub instead, since named subs are not closures in Perl 5.

Quoted text here. Click to load it

Yes, it's absolutely significant. A cutdown version of your code with
enough program round it to test it might look like:

    #!/usr/bin/perl -l

    sub output {
        my $calendarhash = { @_ };
        foreach my $key (sort bydate keys %) {
            print $key;

        sub bydate {
            my $date_a = $calendarhash->;
            my $date_b = $calendarhash->;
            return $date_a cmp $date_b;

    print "FIRST TIME:";
    output a => 1, b => 2;

    print "SECOND TIME:";
    output a => 2, b => 1;

and the output would be


Notice how even though the keys have opposite values the second time,
they still get sorted in the original order. This is because the second
time (and every time thereafter) the bydate sub will still be using the
value of $calendarhash from the first time. This is an unfortunate
limitation in Perl, and the workaround is to use an anon sub instead.

Quoted text here. Click to load it

I don't quite understand your objection here. Using an anon sub is the
only answer. Moving the bydate sub outside the output sub won't compile:
$calendarhash is scoped to the output sub (I presume) so you'll get
'strict' errors. Making $calendarhash global is clearly a bad idea.

What exactly do you think is wrong with

    foreach my $key (
        sort {
            $calendarhash-> cmp $calendarhash->
        } keys %
    ) {

I realise it's a little longwinded, but that's mostly because of your
over-long variable name (it's partly because of the somewhat unfortunate
calling convention of perl's sort). If your sub is so long that a name
like $cal is ambiguous, you need to break it up.

Of course, you could always use something like

    sub sortkv (&\%) {
        my ($sub, $hash) = @_;

        sort {
            local $_ = $hash->;
            my $xa = $sub->();
            $_ = $hash->;
            my $xb = $sub->();
            $xa cmp $xb;
        } keys %$hash;

which would let you write

    for my $key (sortkv { $_-> } %$calendarhash) {

but you probably think that's too obscure as well. Oddly there doesn't
seem to be a Sort::Util or Hash::MoreUtils on CPAN that this might be


Re: variables that won't stay shared

Quoted text here. Click to load it


<snip output illustrating wrong results>

An alternative if the comparator is long and one does not want to inline
it with the sort call would be to use:

#!/usr/bin/perl -l

use strict;
use warnings;

sub output {
    my $cal = { @_ };

    my $bydate_comparator = sub {
        my $date_a = $cal->;
        my $date_b = $cal->;
        return $date_a cmp $date_b;
    for my $key (sort $bydate_comparator keys %$cal) {
        print $key;

print "FIRST TIME:";
output a => 1, b => 2;

print "SECOND TIME:";
output a => 2, b => 1;



(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW: /

Re: variables that won't stay shared

Thanks, Ben and Sinan. I've adopted the inline solution.

Quoted text here. Click to load it

Yes, I was too dense to see it, but I understand it now. My mind just
wasn't tracking with the diagnostics message.

Quoted text here. Click to load it

There's nothing wrong with it. I usually like to use a style where I
place repeated code in named blocks that return values, IOW,

Thinking about this globally, I guess what I was thinking was that I
would use a private method in the module (I have two, one named and the other I know very little about OO Perl,
so my question would be if you can't use internal functions, how would
you write a private method in Perl? With Java, you can embed both
internal methods and internal classes, and in C++ you can use friend
functions as well as internal functions.


Re: variables that won't stay shared

Quoted text here. Click to load it

Yes, don't we all :). Are you saying you have the same sort block in
several places? If you really want to avoid anon subs, you could write a
sub that takes a hashref and does the whole sort:

    sub sorted_calendar {
        my ($cal) = @_;
        return sort {
            $cal-> cmp $cal->
        } keys %$cal;

and then just call that

    foreach my $key (sorted_calendar $calendarhash) {

Quoted text here. Click to load it

Perl has a very minimal OO system, and one of the things it doesn't
provide natively is private methods. If you're learning Perl OO starting
now, and you are expecting it to look like other OO languages you've
come across, you may want to start out learning to use Moose rather than
the native OO. It's a little heavy, but it provides a very complete
object model similar to the one that will be in Perl 6.


Re: variables that won't stay shared

Quoted text here. Click to load it

I am contemplating redoing in an OO style a scheduling application I
built several years ago. The app doesn't need redoing, and there are
several CPAN modules I could use for it, but my motivation is to learn
more about OO Perl than I know, and the only way you can learn
something is to practice it. I'll probably get about 10K messages
about not-reinventing-the-wheel when I start posting my help messages.

In the past year or so, I've had some heavy experience with Java, C++,
and Lisp, along with using Perl on a daily basis. It's become common
for me to experience a frustrating few minutes up to an hour trying to
'fix' non-working code when it dawns on me, 'Oops, wrong language.'
This has been an educational process, and I might start verbalizing
about in on c.l.p.m., but for now I'll relate the most astonishing
moment I've had!

I'm working through Wilensky's book 'Common Lispcraft' (1984) doing
the exercises at the end of each chapter. At the end of chapter 7, one
of the exercises is to build a working inheritance hierarchy. At the
end of chapter 8 we are asked to implement polymorphism. These
exercises don't use pre-built functionality like you do in Java (for
example) by extending or implementing a class -- the student builds
them natively using the core capabilities of the language.

Now, in which programming text in what programming language are you
expected to implement inheritance hierarchies and polymorphism in
chapters 7 and 8 of the basic text? Lisp is a language from the 1950s
yet could do stuff in the mid-1980s that the BIG languages can't yet
do! Put this in your pipe and smoke it!


Site Timeline