Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

why does push not default to $_?

by LanX (Sage)
on Dec 04, 2008 at 21:33 UTC ( #728108=perlquestion: print w/replies, xml ) Need Help??

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

I've been asked why it's not possible just to write push @arr; to push $_ (like print for instance)

I meditated but couldn't find a special reason, do you know any?

Cheers Rolf

Replies are listed 'Best First'.
Re: why does push not default to $_? (simple)
by tye (Sage) on Dec 05, 2008 at 04:07 UTC

    print has a quite complex signature. It must distinguish between print $this; and print TO_THIS;, for example. So it also can tell between print @empty; and print;.

    push is quite simple. You can write your own sub that offers the exact same interface:

    sub Push(\@@);

    So what to push onto the array is simply a (flattened) list (of scalar values). So push can't tell the difference between push @a; and push @a, @empty;... unless its simple interface gets special-cased for this. I'm not surprised that such special-casing was not deemed worth allowing the questionable usage of an implied $_.

    At some point, somebody did some extra work to add the warning you get. The code you want would be added at the same point, but it would have to synthesize code to push the current value of $_ onto the stack before the push opnode (or thereabouts). That is certainly more work than just emitting a warning.

    But then you'd have to fight the backward-compatibility battle -- which, frankly, I would consider a rather silly battle since transforming something that is useless and emits a warning into something useful (but perhaps of dubious wisdom) seems quite reasonable regarding backward compat.

    - tye        

      Am I understanding you right, the prototyope mechanism of builtins like push can't distiguish between missing parameters and empty parameters. But some special functions like "print" and "splice" have a proper non-prototype-based interface? (*)

      I'm not really missing that feature, it's just a meditation about design and orthogonality.

      IMHO, it would be much easier to prog if perl had more axiomatic rules instead of a bunch of special exeptional cases. Something like "if the last obligatory list @ or scalar $ in a prototype is ommitted in the code, $_ will be included instead throwing an error".

      Or as more flexible approach "you can use "@_" and "$_" in prototypes to flag parameters which default to $_ if missing"

      anyway, perl6's solution to flag these functions with a trailing . and making them methodes of an invisible $_ seems reasonable! (eg  .print; .push @a;)

      Cheers Rolf

      UPDATES:

      (*) Must be! That's why prototype returns undef for print and split, showing they are not overridable!

      DB<10> use Data::Dumper DB<11> print Dumper prototype "CORE::split" $VAR1 = undef; DB<12> print Dumper prototype "CORE::print" $VAR1 = undef; DB<13> print Dumper prototype "CORE::push" $VAR1 = '\\@@';

      () But I don't know if it makes sense to push a global like $_ on the stack...

        Or as more flexible approach "you can use "@_" and "$_" in prototypes to flag parameters which default to $_ if missing"
        Is this a claim (that you can already do this) or a suggestion? If it's a claim, then note that _ is already a valid character in prototypes for a scalar argument defaulting to $_, as you want. If it's a suggestion, then I think that having a prototype syntax like @_ would be very confusing (besides being ambiguous, given that it conflicts with a currently valid, although useless, prototype), since @_ already has a quite different meaning.

        By the way, notice that Params::Validate has a very rich defaults syntax for this sort of thing. In particular, you can do something like

        validate_pos 1, ( { default => $_ } ) x ( @_ - 1 )

        UPDATE: Oops, that last snippet doesn't make any sense. Indeed, as I think about it further, what does it mean to have an array of values, all of which default to $_ if absent? I think it's best to stick with the case of allowing explicitly listed parameters to default:

        validate_pos 1, ( { default => $_ } ) x 57

Re: why does push not default to $_?
by tilly (Archbishop) on Dec 05, 2008 at 00:51 UTC
    I would guess that Larry never thought that anyone really wanted that shortcut. So it never happened.

    While I wouldn't personally object if it was added to Perl, I would object if I had to maintain code that used that shortcut...

Re: why does push not default to $_?
by ikegami (Pope) on Dec 04, 2008 at 21:38 UTC

    That would break

    push @a, @b;

    It would push $_ when @b is empty instead of push nothing as expected.

    Update: Or maybe not. That's doesn't break print, after all.

      Good argument, but whats the difference to
      print @b;
      if @b is empty? It doesn't print $_
      for (1..13) { print @b; }
      Furthermore there is no error with:
      push @a, @b;
      but you get a warning with
      push @a;
      so perl can distinguish between missing parameters and empty parameters...

      Cheers Rolf

        Yeah, I already noticed and updated my node.

        The only possible reason I could see if an undue burden on the parser, since it would be the first function to default the second argument. You could send a perl (wishlist) bug report?

Re: why does push not default to $_?
by perreal (Monk) on Dec 06, 2008 at 03:00 UTC
    Well, I think print and push are different in that when you see:
    print;
    it feels like you want to print something, that thing being directly related to the context (default arg) makes sense. on the other hand:
    push @a;
    feels like we want to push @a to some place... like a stack. If there was a default stack than the right action would be to push @a to the default stack. So, I guess it is more about linguistics than implementation,

      There is a default stack. At least according to shift and pop.

      Making 1-arg push (and unshift) work with @_ (or @ARGV) as a default 1st arg would, IMHO, be more consistent (I have accidentally expected this behaviour once). Unfortunately, its not terribly useful. I don't find myself adding to @_ frequently.

        It's not a good idea. The only thing you could push onto the "stack" is would be the contents of an array. For example, you can't make push $foo; work without breaking push @foo, $x;. The usefulness of the feature is just too limited to compensate for the confusion the its implementation would cause.

Re: why does push not default to $_?
by ptoulis (Scribe) on Dec 06, 2008 at 00:48 UTC
    The Camel book gives a good hint: "The underline is the underlying operand in certain operations."

    These "certain operations" are the unary functions and the iterators like foreach,for, map{}, grep{}. The idea is that in a unary function there is only one operand and since these are used very often and Perl is Huffman encoded, it makes great sense to have a special name when this operand is not specified.

    The push function is not unary and it would be a bad idea to include special names in its operands. Moreover, push mutates its first operand and it would really be a bad idea to change data and at the same time hide from the developer how the data is being changed.
      > Moreover, push mutates its first operand and it would really be a bad idea to change data and at the same time hide from the developer how the data is being changed.

      Well for me, calling push with only one parameter is quite obvious. At least not less than print without parameter.

      Please, in which chapter did you find that quote in the camel book?

      Cheers Rolf

      UPDATE: here what I found in 2.9.3 Global Special Variables
      Here are the places where Perl will assume $_ even if you don't use it:
      
          *      Various unary functions, including functions like ord and int, 
       as well as all the file tests (-f, -d) except for -t, which defaults to STDIN.
          *      Various list functions like print and unlink.
          *      The pattern-matching operations m//, s///, and tr/// when used 
       without an =~ operator.
          *      The default iterator variable in a foreach loop if no other variable
       is supplied.
          *      The implicit iterator variable in the grep and map functions.
          *      The default place to put an input record when a <FH> operation's
       result is tested by itself as the sole criterion of a while test. Note that
       outside of a while test, this will not happen. 
      
      Mnemonic: underline is the underlying operand in certain operations.

      Well various doesn't sound very specific, and print and unlink are not unary.

        Well for me, calling push with only one parameter is quite obvious. At least not less than print without parameter.
        The difference is that print does not alter its operands but push does. Even ignoring these there is hardly a good reason to use $_ for push. For example, in iterators which set the $_ you might want to use something like: for(1..100) { push @a;}, but still you would be better going by push @a,(1..100);
        Please, in which chapter did you find that quote in the camel book?
        You can find the quote in Chapter 28-Special Names, page 659.
Re: why does push not default to $_?
by JavaFan (Canon) on Dec 06, 2008 at 02:13 UTC
    I meditated but couldn't find a special reason, do you know any?
    Simple, because noone found it interesting enough to actually sit down and write a patch. That's how perl5 development works. New features don't get added if enough people want them. New features get added if one person wants it badly enough to write a patch.

    So, if you want push to accept a default second argument, write a patch and submit it. I'm not in charge, so I won't have a final say whether it will get in, but if you have the patch, you'll have a pretty good chance. Without the patch and just the wish, chances are almost non-existant.

      I never said I want that push accepts a default second argument, I just want a consistent and orthogonal behaviour.

      It may be the occupational disease of a mathematician, but I just prefer a predictabel symmetry in logical systems!

      Cheers Rolf

        I never said I want that push accepts a default second argument, I just want a consistent and orthogonal behaviour.
        Then Perl isn't your forte. Perl was designed with the human mind and natural languages in mind - neither of which are consistent or orthogonal. (BTW, my 'you' was a generic you, not specifically aimed at you).
        It may be the occupational disease of a mathematician, but I just prefer a predictabel symmetry in logical systems!
        Guido van Rossum is a mathematician as well. Hence Python. (This isn't meant as a jab at Python - far from it; Python is a nice language, it just has a different philosophy than Perl).
Re: why does push not default to $_?
by toolic (Bishop) on Dec 04, 2008 at 21:40 UTC
    Update: OK, I sit corrected :) I guess I missed the point of the question.

    push is a Perl built-in function which requires 2 arguments.

    Of related interest: Builtin functions defaulting to $_

      First of all, that's not true. The following are all acceptable:

      push @a; push @a, 'a'; push @a, 'a', 'b';

      Second, if it was true, that doesn't answer why the second parameter can't be optional, defaulting to $_.

        push @a;
        It is syntax which will compile, but it does generate a warning. Can you show an example of where this would be used?
        use strict; use warnings; use diagnostics; use Data::Dumper; my @a = 1..3; push @a; print Dumper(\@a); __END__ % ./728108.pl Useless use of push with no values at ./728108.pl line 9 (#1) (W syntax) You used the push() or unshift() function with no argum +ents apart from the array, like push(@x) or unshift(@foo). That won't usually have any effect on the array, so is completely useless. It +'s possible in principle that push(@tied_array) could have some effec +t if the array is tied to a class which implements a PUSH method. If + so, you can write it as push(@tied_array,()) to avoid this warning. $VAR1 = [ 1, 2, 3 ];
Re: why does push not default to $_?
by mr_mischief (Monsignor) on Dec 08, 2008 at 21:49 UTC
    My first guess would be that push is paired with pop. You might very well want to say, for example, pop @foo; without putting what was popped anywhere. If push() took $_ by default, one might expect pop() to assign to $_ by default. Logical pairs that don't both deal with the same implicit variable should probably neither one do so.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://728108]
Approved by Arunbear
Front-paged by Arunbear
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2021-11-28 23:26 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?