Stegalex has asked for the wisdom of the Perl Monks concerning the following question:

The following code will work but if I run it with the -w flag on, I get the following warning: Variable "$self" will not stay shared at /export/home/webadmin/webmin/perl/docSearch.pm line 380.I would like to eradicate this message so that I don't fill up the error log with it. Thanks for any help!
sub sort_results { #======================================== # Sort results in descending order # by date and ascending by document name # within a date. #======================================== my $self = shift; @{$self->{_search_hits}} = sort desc_by_date_asc_by_name @{$self->{_ +search_hits}}; sub desc_by_date_asc_by_name { $self->{_database}[$b]->{numeric_date} <=> $self->{_database}[$a]- +>{numeric_date} or $self->{_database}[$a]->{document_name} cmp $self->{_database}[$b] +->{document_name} or $a <=> $b; } }

Replies are listed 'Best First'.
Re (tilly) 1: Variable will not stay shared in subroutine
by tilly (Archbishop) on Jan 09, 2002 at 03:43 UTC
    Juerd hit the problem. The underlying issue is a naming issue, both subroutines have globally visible names, but if you call them both multiple times, there are many different lexical variables those names could be bound to. Perl guesses that the inner remains bound to the first lexical it ever saw that associated with, and that is likely wrong. (This is a complex issue, but there is no way past it.)

    Here is a quick rewrite:

    sub sort_results { #======================================== # Sort results in descending order # by date and ascending by document name # within a date. #======================================== my $self = shift; my $database = $self->{_database}; my $sort_sub = sub { $database->[$b]->{numeric_date} <=> $database->[$a]->{numeric_date +} or $database->[$a]->{document_name} cmp $database->[$b]->{document_na +me} or $a <=> $b; }; @{$self->{_search_hits}} = sort $sort_sub @{$self->{_search_hits}}; + }
    Note that the use of an anonymous function means that the function is lexically named, and is always bound to the lexical variable in its name space. The previous naming issue is now just gone.
Re: Variable will not stay shared in subroutine
by Juerd (Abbot) on Jan 09, 2002 at 03:28 UTC
    From perldiag:
    Variable "%s" will not stay shared</strong

    (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 *first* call to the outer subroutine; in this case, after the first call to the outer subroutine is complete, the inner and outer subroutines will no 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 subroutines 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 that reference variables in outer subroutines are called or referenced, they are automatically rebound to the current values of such variables.

    2;0 juerd@ouranos:~$ perl -e'undef christmas' Segmentation fault 2;139 juerd@ouranos:~$

      Or, in even more other words, your variable $self will be frozen (in a closure) by the subroutine desc_by_date_asc_by_name() when sort_results() is called for the first time (in case you were wondering).

      Update: added parenthetical "closure" clarification.

      dmm

      You can give a man a fish and feed him for a day ...
      Or, you can
      teach him to fish and feed him for a lifetime
(Ovid) Re: Variable will not stay shared in subroutine
by Ovid (Cardinal) on Jan 09, 2002 at 03:42 UTC

    Juerd answered this, but I just wanted to point out that I find the docs a bit misleading on this point. It refers to inner and outer subroutines, but does not make it clear that subs cannot be lexically scoped (I understand that this may change in Perl6). Thus, anytime I see subroutines nested like this, I look for errors in the code stemming from the misunderstanding. Looks like you found one of those errors :)

    Subroutines are entries in the current namespace's symbol table (in a typeglob slot) and this does not allow for nesting. As the docs explain, this can be gotten around by using an anonymous subroutine because these get stuffed in a scratchpad, thus making them lexically scoped.

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Variable will not stay shared in subroutine
by Anonymous Monk on Aug 29, 2014 at 17:05 UTC
    For the benefit of others googling this issue, am I correct to assume that what most people *mean* when they hit this problem in their (usually different to this example) code, is to be doing the following instead? our $self = shift; I gather this is a very common issue in mod_perl, where I'm hoping the above is the correct solution to what the coder probably mean to be a global variable.
      The correct solution is not to declare a named subroutine inside a named subroutine.
      لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
        I found this thread when looking for explanation for this message. In my case the solution is using "our" instead of "my". As a side effect the variable is a global with limited visibility.