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

Here is the perl I can’t figure out:
$self->{'Post'} = ($args{'Post'} or sub {1;});
This is from a class constructor (“new”); it is setting the class hash variable ‘Post” to a subroutine that was passed in ($args{‘Post”}). If that is false or not defined, then it sets the class variable ‘Post’ to sub {1;}. This is where I am lost. What is sub {1;} ? A forward declaration to a subroutine which is… ??? I am guessing that { ;} is part of the sub declaration and not a hash, but I can’t remember what “1” should represent. Or maybe this is something else entirely.

Replies are listed 'Best First'.
Re: what is sub {1;}
by ikegami (Patriarch) on May 27, 2008 at 07:56 UTC

    sub {1;} returns a reference to a subroutine that returns 1 when invoked.

    >perl -le"$cb = sub {1;}; print $cb->()" 1
Re: what is sub {1;}
by moritz (Cardinal) on May 27, 2008 at 07:58 UTC
    sub {1;} is an anonymous subroutine that always returns 1.
    my $x = sub {1; }; print $x->();
      and what would be the use of such construct?
        As a default value.

        Suppose you write a sub (or module) that processes some values, and you want to offer the caller the possibility to filter some of them. Now you've got two options:

        sub process { my ($data, $filter) = @_; # lengthy calculations with $data here ... # in that length calculation you have to decide # if you continue with your calculation: for (@$data){ if ($filter) { if ($filter->($_)){ push @$data, other_lengthy_calculation($_); } } else { push @$data, other_lengthy_calculation($_); } } # second option: sub process { my ($data, $filter) = @_; # provide a default value for $filter $filter = sub {1;} unless $filter; # lengthy calculations with $data here ... # in that length calculation you have to decide # if you continue with your calculation: for (@$data){ if ($filter->($_)) { push @$data, other_lengthy_calculation($_); } }
        You can see that the construct with the default value is much shorter (3 instead of ~8 lines), and it's much cleaner.

        If you're interested in more details on callbacks, anonymous subs and many more advanced techniques, I strongly recommend the book "Higher Order Perl" by Mark Jason Dominus.

        It allows

        my $rv = $args{'Post'} ? $args{'Post'}->() : 1;
        to be simplified to
        my $rv = $args{'Post'}->();

        Or if the return value isn't checked, it allows

        $args{'Post'} and $args{'Post'}->();
        to be simplified to
        $args{'Post'}->();

        (sub{} would have been sufficient in the latter case.)

        It's impossible to say without seeing the rest of the code. I expect that in context it's a sensible default if the user doesn't specify a function himself.
Re: what is sub {1;}
by mhearse (Chaplain) on May 27, 2008 at 09:03 UTC
Re: what is sub {1;}
by rovf (Priest) on May 27, 2008 at 09:00 UTC
    Actually, the semicolon could be omitted: sub {1} would do equally well. Note that sub followed by an open brace constructs a reference to an unnamed subroutine, and that the last expression (in this case: the only one) in a subroutine is the value returned from the subroutine. An alternative way to write this would be
    sub {return 1;}
    -- 
    Ronald Fischer <ynnor@mm.st>
Re: what is sub {1;}
by TGI (Parson) on May 27, 2008 at 17:05 UTC

    As others have said, the code provides a default anonymous sub for the 'Post' attribute of $self. Since the anonymous sub aspect of this has been well covered, I'll comment on the default value side of things, with a slight detour into 'or' vs '||';

    The code snippet you posted threw me off balance for half a second--setting default values is usually done using '||'--the high precedence logical or operator.

    Perl has two logical or operators, '||' and 'or'. They identical except in terms of precedence. '||' has a high precedence and 'or' has a low precedence.

    $foo = $bar || 'baz'; # is identical to $foo = ( $bar or 'baz');

    Common usage for each operator:

    open( $fh, '>', $filename ) or die "Unable to open file: $!"; my $foo = $bar || 'baz';

    Now, lets look at a couple ways to set a default value:

    # Original code $self->{'Post'} = ($args{'Post'} or sub {1;}); # High precedence or $self->{'Post'} = $args{'Post'} || sub {1}; # Ternary operator $self->{'Post'} = $args{'Post'} ? $args{'Post') : sub {1}; # Using '||' for a numeric value. $self->{'Number'} = $args{'Number'} || 10;

    This idiom is a common, compact, and readable way to set default values. However there is a trap for the unwary here. If the value you are testing may legitimately evaluate to false, your default value will be spuriously assigned. Take a look at the code below for an example of this bug.

    foo(); foo(23); foo(0); sub foo { my $number = shift || 10; print "My number is $number\n"; } __END__ #OUTPUT: My number is 10 My number is 23 My number is 10

    So, if you use this idiom, make sure you understand how your acceptable values are treated in boolean context (whether they evaluate to TRUE or FALSE).

    Update: as DrHyde points out, if you are using Perl 5.10, the truly lovely defined-or operator solves this problem very nicely.

    foo(); foo(23); foo(0); sub foo { my $number = shift // 10; print "My number is $number\n"; } __END__ #OUTPUT: My number is 10 My number is 23 My number is 0


    TGI says moo

      However there is a trap for the unwary here. If the value you are testing may legitimately evaluate to false, your default value will be spuriously assigned.

      That's solved by using the defined-or operator "//" that's new in perl 5.10. However, because it's so new it's probably not a good idea to use it yet for anything you upload to the CPAN :-)