in reply to Re^5: why does push not default to $_? (simple)
in thread why does push not default to $_?

I know that it doesn't have the elegance of what you're looking for, but why not just build in the default?
sub push (\@;@) { CORE::push ( @{+shift}, @_ ? @_ : $_ ) }
(Incidentally, this works for me, but is it guaranteed to do so? I seem to remember—but can't find—a discussion here a while back indicating that, while arguments are often evaluated left-to-right, they aren't guaranteed to be. Do we know that the shift will happen before we test the value of @_?)

UPDATE: LanX points out an extremely good answer to “why not?”, namely, “Because it behaves like accessors that get/set based on whether they have/don't have an argument, and passing an empty list leads to surprises.”

Replies are listed 'Best First'.
Re^7: why does push not default to $_? (simple)
by ikegami (Patriarch) on Dec 07, 2008 at 19:04 UTC

    Operands are evaluated left-to-right except for assignment operators. Even right-associative ** evaluates its operands left-to-right. It's not documented, but I don't see it changing. From what I've read, I'd even say there's a desire to fix a case where it isn't, should one be found.

    If you wanted to avoid relying on the undocumented feature, you'd do

    sub push (\@;@) { my $array = shift; CORE::push ( @$array, @_ ? @_ : $_ ) }

    Of course, both yours and this modified version fail to handle @b=(); push @a, @b; properly.

Re^7: why does push not default to $_? (simple)
by LanX (Saint) on Dec 07, 2008 at 19:45 UTC
    sub push (\@;@) { CORE::push ( @{+shift}, @_ ? @_ : $_ ) }
    already tried it, it's a trap forget it. If you do push (@a,@b) and @b is empty, then $_ will be pushed, and that's definetly not what you expect!

    If there is any feature request, which might make sense on the wishlist for the next perl5 version, it's to add a prototype symbol for "list defaulting to $_". "_" is already a symbol for "scalar defaulting to $_" which must be placed as last symbol before ";".

    So I suggest double underscore "__" shall mean "list defaulting to $_".

    I remember slightly that in PBP one can find a somehow similar reasoning why not to use prototypes! *

    If anybody knows a way to already implement push() this way, please try these testcases:

    use subs 'push'; sub push (\@;@) { # print $_[0],$_[1]; CORE::push( @{+shift}, $_[0]? @_ :$_) ; } $\="\n"; my @a; $_="_"; print "--- one parameter"; push @a; print @a; print "--- long list of parameters"; @b=("x","y"); @a=(); push @a,@b; print @a; print "--- one element"; @a=(); push @a,"z"; print @a; print "--- one element list"; @a=(); @b=("z"); push @a,@b; print @a; print "--- empty list"; @a=@b=(); push @a,@b; print @a; __END__ --- one parameter _ --- long list of parameters xy --- one element z --- one element list z --- empty list _

    Cheers Rolf

    UPDATES: Chapter9 "Subroutines"/Subchapter "Prototypes" -> "Don't use prototypes" ... The examples show that they mostly confuse because they often force scalar context!