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

Hi Monks, I'm attempting to assign a function to a variable and then call the function from the variable. For example:

if ( $file =~ /^London/ ) { $time_zone_func = gmtime; } else { $time_zone_func = localtime; } my $prev_days = $4 * 86400; if ( $prev_days ) { $TIMESTAMP = strftime($date_format, $time_zone_func(time - $prev_day +s)); } else { $TIMESTAMP = strftime($date_format, $time_zone_func(time)); }

This does not work and I'm guessing that it's not possible, but thought I'd ask the Guru's to be sure. Obviously, there is a workaround, but this seemed like the least amount of code to accomplish the task if it worked.

Thanks a lot

Replies are listed 'Best First'.
Re: Variable behaving as a function call
by AnomalousMonk (Archbishop) on May 11, 2016 at 19:19 UTC

    c:\@Work\Perl\monks>perl -wMstrict -le "sub hiya { print 'hello there ', $_[0]; } hiya('sailor'); ;; my $coderef = *hiya{CODE}; $coderef->('everybody'); " hello there sailor hello there everybody

    Update: Please see  -> operator discussion The Arrow Operator in perlop;  *foo{THING} discussion in Typeglobs and Filehandles in perldata.


    Give a man a fish:  <%-{-{-{-<

      my $coderef = \&hiya; is far more conventional, but both are ok for subroutines.

      Neither will work for operators such as gmtime and localtime, though.

      Since 5.16:

      my $time_zone_func = $file =~ /^London/ ? \&CORE::gmtime : \&CORE::localtime; strftime($date_format, $time_zone_func->(time))

      Backwards compatible:

      my $time_zone_func = $file =~ /^London/ ? sub { gmtime($_[0]) } : sub { localtime($_[0]) }; strftime($date_format, $time_zone_func->(time))
      or
      my $time_zone_func = sub { $file =~ /^London/ ? gmtime($_[0]) : localtime($_[0]) }; strftime($date_format, $time_zone_func->(time))
        ... \&hiya; is far more conventional ... Neither will work for operators such as gmtime ...

        Oops... Should've remembered that one!


        Give a man a fish:  <%-{-{-{-<

      works like a charm. Thanks!

Re: Variable behaving as a function call
by LanX (Saint) on May 11, 2016 at 19:39 UTC
    Try
    $time_zone_func = sub {gmtime()}; # then print $time_zone_func->(); # or print &$time_zone_func;

    Though in this case a normal named function seems to be the easiest approach.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

Re: Variable behaving as a function call
by BrowserUk (Patriarch) on May 11, 2016 at 19:44 UTC

    If you are on Perl 5.16 or above, you can take references to most built-in functions, using the syntax:  \&CORE::builtin.

    If you are on an earlier version, that isn't allowed, so you'd need to use wrappers:

    $b = 0; $x = $b ? sub{ gmtime( @_ ) } : sub{ localtime( @_ ); }; print $x->( 123456 );; 1 0 0 1 0 70 4 0 0 $b = 1; $x = $b ? sub{ gmtime( @_ ) } : sub{ localtime( @_ ); }; print $x->( 123456 );; 1 0 0 1 0 70 4 0 0

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
      You need to replace @_ with $_[0] because the argument is evaluated in scalar context.
Re: Variable behaving as a function call
by 1nickt (Canon) on May 11, 2016 at 19:44 UTC

    Hi dirtdog,

    I believe you are looking for a CODEREF. You could do:

    my $time_zone_func = ( $file =~ /^London/ ) ? sub { gmtime shift } : sub { localtime shift };
    to create a reference to an anonymous subroutine.

    You dereference the coderef with &{ $ref } so you would call it as:

    $foo = &$time_zone_func( time );
    or
    $bar = $time_zone_func->( time );

    Hope this helps!


    The way forward always starts with a minimal test.