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

Here at plasmasturm I see the following little sub:

sub strip { s/\A\s+//, s/\s+\z// for my @r = @_; @r }

Formatting that out a bit, it's:

sub strip { s/\A\s+//, s/\s+\z// for my @r = @_; @r }

So, I suppose it's stripping whitespace off of every element in @_. I see what the regexen are doing, but how is that "for" loop working? With the equals sign there ... I just don't get it. Regarding the comma, I suppose it's just a separator that tells perl to just evaluate one s/// after the other.

Further down in the code, there's this "for" loop:

for ( 1 .. 3 ) { run_fork { child { # [snip] some stuff ... exit; } } }

Are run_fork and child function calls? They look strange to me. The only place I think I've ever seen functions that take a block of code after them is with map and grep... How does one write a sub that takes a block of code (in curlies) like that?

Actually, I've used {}'s to make hash refs for passing a handful of named params to a sub, but I don't think that's what's going on here...

Replies are listed 'Best First'.
Re: How does this code work? (from "Perl is Unix")
by bobf (Monsignor) on Nov 06, 2009 at 06:00 UTC

    I'll take the first one, but I haven't played with forks so I'll leave that to wiser monks.

    s/\A\s+//, s/\s+\z//
    You are correct that this code is stripping white space. More precisely, it is stripping leading and trailing white space. In fact, this task is performed so often there is a snippet in perlfaq4. If you are wondering about the use of \A and \z, see perlre:
    The \A and \Z are just like "^" and "$", except that they won't match multiple times when the /m modifier is used, while "^" and "$" will match at every internal line boundary. To match the actual end of the string and not ignore an optional trailing newline, use \z.

    The other bit:

    for my @r = @_;
    does a couple of things. The for causes the preceding expression (regexen) to be executed for each of the items in the following list (the array @r). The @r = @_ makes a copy of the parameters passed to the subroutine (in @_, see perlvar) before they are used. This is important because the values in @_ are aliases to the original values (in the calling code, see perlsub) and if a copy was not made the original values would be modified. You can test this pretty easily - just change the code to use @_ directly and see what happens to the original values

    Update: There are a couple of other things worth mentioning. The way the for loop is constructed, the default variable $_ is used (see perlvar), which aliases the elements in @r. Second, the final line, which contains a solitary @r, is a shorthand way of specifying the return value of the routine (remember, the elements of @r were changed via aliasing in the for loop). See perlsub:

    If no return is found and if the last statement is an expression, its value is returned.
    I won't get into how the value of the expression is determined as it is context dependent and can be tricky to understand.

      Oh! I see now. This:

      s/\A\s+//, s/\s+\z// for my @r = @_;

      is the same as

      my @r = @_; s/\A\s+//, s/\s+\z// for @r;


Re: How does this code work? (from "Perl is Unix")
by colwellj (Monk) on Nov 06, 2009 at 05:45 UTC
    sub strip { s/\A\s+//, s/\s+\z// for my @r = @_; @r }
    The for is acting on @_ which in perl is 'the array i'm currently looking at' and in this scope is the list you passed to strip. ugly code though.

    for the other use Proc::Fork; is probably of interest

    run_fork -creates a fork for the block
    child - declares the block to run with a child

      I'm not concerned with forking code here, per se. What I'd just like to know is, what does something like

      foo { bar { ... } baz { ... } }

      even mean? I know what $, @, %, and & signify, and I know what sub {...} gets me, but it's just completely flying over my head what I'm looking at here with these barewords followed by code in curlies. Am I missing something obvious? :)

      I didnít aim for clarity in that bit. I wanted to waste the least space possible on code to perform this function, because I was contrasting with Ruby and Python examples, where there is no need to write any code for this because both languages include strip methods in their built in String classes.

      Maybe I should lobby for the inclusion of a strip function in Scalar::Util. (It could even be written in XS, and therefore go faster than regexes. Hmm. Thereís a thought.)

      Makeshifts last the longest.

        Is it just me or does the whole bunch of Utils modules seem very haphazard, from namespace choices to grouping
Re: How does this code work? (from "Perl is Unix")
by duelafn (Parson) on Nov 06, 2009 at 12:46 UTC

    run_fork and child are function calls declared with the & prototype (See perlsub: Prototypes). So, yes, they auto-subify their first argument (as though you had called run_fork(sub { ... })).

    Good Day,

      Ohhhhhh. I see. Thank you for pointing that out! I've avoided using Prototypes in my own code, and had almost forgotten about them.

      FWIW, I much prefer the more explicit syntax that you gave as an equivalent example. That is, something like this seems sensible and obvious to me:

      #!/usr/bin/env perl use strict; use warnings; sub call_it { my $fn_ref = shift; &{$fn_ref}(); } call_it( sub { print "hi\n" } ); call_it( sub { print "bye\n" } );

        If you understand map { foo($_) } then this code shouldnít give you any trouble.

        Makeshifts last the longest.

Re: How does this code work? (from "Perl is Unix")
by targetsmart (Curate) on Nov 06, 2009 at 05:55 UTC
    If you dont understand a block of code, just simplify it to the maximum extent possible. break that complex statement into relevant simpler statements, and try to understand that with help of the occean of documentation that perl has here Perl documentation.

    -- 'I' am not the body, 'I' am the 'soul', which has no beginning or no end, no attachment or no aversion, nothing to attain or lose.
Re: How does this code work? (from "Perl is Unix")
by Aristotle (Chancellor) on Nov 07, 2009 at 03:35 UTC

    Just for completenessí sake, that strip function code is a condensed syntactic (near) equivalent of this function:

    sub strip { my @r = @_; for ( @r ) { s/\A\s+//; s/\s+\z//; } return @r; }

    But I didnít want to spend 6 lines on a routine that is completely incidental to the main point of the code, and which I put there only to emulate the exact behaviour of the Ruby and Python counterparts. If it were in a module with string functions, I would write it in the long-hand form. Programming is writing and code is literature. Sometimes you need to linger on the details and sometimes they would only derail the pacing.

    Makeshifts last the longest.