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

Dear Perl Monks,

I'd like to write a sub that I could use like this :

display_thing foreach(@things);

having $_ passed to display_thing.

Actually, I need to write :

display_thing $_ foreach(@things);

and my sub looks like this :

sub display_thing { my ($t) = @_; print $t; }
Is there a way to do this ?

Thank you,

Bruno.

Replies are listed 'Best First'.
Re: Is it possible to write a sub that understand default variables ?
by Corion (Patriarch) on Dec 24, 2007 at 11:27 UTC

    If you're using 5.10, you can use the new _ (underscore) prototype to create subroutines that magically use either a passed parameter or $_:

    sub display_thing (_) { print $_[0] }; $_='Hello 5.10'; display_thing;

    Another way would be to just wrap display_thing with your own wrapper that handles the decision between $_ and @_:

    my $old_display_thing = \&display_thing; *display_thing = sub { if (@_) { &$old_display_thing(@_) } else { &$old_display_thing($_) }; };

    But if you're rewriting or wrapping display_thing (and I see no way around rewriting or wrapping it), why not rewrite or wrap it to accept multiple arguments straight away?

    sub display_thing { for (@_) { print "Displaying thing >$_<\n"; }; };

      I had to look up the perl 5.10 documentation - found this in perldoc perlsub
      As the last character of a prototype, or just before a semicolon,
      you can use "_" in place of "$":
      if this argument is not provided, $_ will be used instead.
      Yes, my favorite solution is really the 5.10 way :)

      Thank you.

Re: Is it possible to write a sub that understand default variables ?
by FunkyMonk (Bishop) on Dec 24, 2007 at 11:24 UTC
    my @things = 1.. 5; display_thing() foreach @things; sub display_thing { my $t = $_; print $t }

    works fine. If you really want to call display_thing without the brackets either declare the subroutine before you call it, or use prototypes (but you don't want to do that, honest).

Re: Is it possible to write a sub that understand default variables ?
by ikegami (Patriarch) on Dec 24, 2007 at 17:30 UTC

    Using $_ as the default for a function that normally accepts a list is a bad idea since @a = (); display_thing(@a); would use $_, and that would break the expected behaviour.

    However, if you want a function that accepts either zero or one argument, you could do that as follows (pre 5.10):

    sub func { my $s = @_ ? $_[0] : $_; ... }

    And if you want to arg to be called $_ in your sub:

    sub func { for (my $s = @_ ? $_[0] : $_) { ... } }

    This last one is particularly ugly. I only use it when the sub consists entirely of s/// statements.

      I just tried "empty @a" against my solution. The _ prototype forces scalar context on the first argument:

      /opt/perl/bin/perl5.10.0 -M5.10.0 -e 'sub display(_){say $_[0]};@a=(); +display(@a);push@a,"x";display(@a)'

      Whether that is considered to be unintuitive or not depends on the user I guess

        No surprises there
        >perl -le"@a=qw(A B C); print lc @a" 3