in reply to Re^4: Shifty Politics
in thread stoping and restarting a loop

Thanks. This and Shift versus Sanity are very interesting. I'm still learning all the why's and wherefor's of perl syntax and semantics. I probably will be for some time to come. I will just about have mastered it, and Perl6 will hit the streets! Hopefully, enough of it will carry over to not invalidate the exercise.

A couple of questions arising:

Wouldn't this

sub fooge_default { my $self = shift; $self->fooge(@_); # Blind parameter passing }

be better done as this?

sub fooge_default { my $self = shift; goto &$self->fooge; # Not entirely sure of the syntax }

vis

The goto-&NAME form is highly magical, and substitutes a call to the named subroutine for the currently running subroutine. This is used by AUTOLOAD() subroutines that wish to load another subroutine and then pretend that the other subroutine had been called in the first place (except that any modifications to @_ in the current subroutine are propagated to the other subroutine.) After the goto, not even caller() will be able to tell that this routine was called first.

Also, I realise that finding good examples is always a problem, but your example of where shift is dangerous isn't the fault of shift but of the logic of the test.

Using the correct test in the right place make it irrelavent which method is used to access the args I think?

sub fooge { die "fooge() needs two arguments\n" unless (@_ ==2); my ($foo, $bar) = (shift, shift); # or @_ are equally safe. # ... }

Well It's better than the Abottoire, but Yorkshire!

Replies are listed 'Best First'.
Re^6: Shifty Politics
by tadman (Prior) on Sep 10, 2002 at 15:46 UTC
    I'd rather have two dozen shifts than a single goto. There's something almost assembler-like about that version of the goto statement. I've used it before, but only inside an AUTOLOAD. That's also only because in my opinion, AUTOLOAD is lacking some important functionality, like being able to return a subroutine reference that is automatically injected into the namespace to plug a hole. That, however, is another story.

    Further, moving the @_ check to the front of the subroutine might not be viable. Or you could have something like this:
    sub fooge { my ($foo, $bar, @baz) = @_; # ... if ($foo->isa('Acme::Frobnicator')) { die "Missing 'baz' parameter to fooge()\n" unless (@baz); $foo->frob(@baz); # ... } # ... }
    You can do that with shift, sure, but it's not as concise.

    Now regardless, I still can't see why using shift is better in any respect. Where do you draw the line? Four parameters? Five? And why draw the line at shift?
    sub fooge { my ($foo, $bar) = (pop, pop); }
    You'll note that shift is more verbose, and also permanently modifies @_. I'd rather have it there intact for debugging purposes. For example:
    sub blarg { my ($foo, $bar, $bork) = @_; # ... if (computer_is_on_fire()) { die "Apocalyptic end of blarg(@_)\n"; } }

      I'd rather have two dozen shifts than a single goto.

      I wonder if that particular form of goto were renamed to

      forward_my_args_without_the_need_to_build_a_new_stackframe_or_replicate_the_args_array()

      would you still be so reluctant to use it? (Apart from the stupid long name of course:)

      moving the @_ check to the front of the subroutine might not be viable

      An example of when this might be the case?

      I still can't see why using shift is better in any respect

      I don't think I ever said it was better. I just fail to see why one peice of perl syntax should be eshewed simply on the basis of prejudice.

      My use in the original code was simple, clear, precise and correct. The only example you have given as to why it should not be used that (to me) holds water, is your example of making it easier to debug if @_ is left intact, but even then, placing a breakpoint on the initial list assignment goes a long way to negating that arguement. Especially as you are advocating using shift to obtain the first arguement where that happens to be a class handle.

      As for where I would draw the line, a guess that would be wherever it makes most sense given the particular example I am coding. Given time and more experience with perl, this could change.


      Well It's better than the Abottoire, but Yorkshire!
        My argument is simply that using shift to extract several arguments is usually inefficient and, by induction, not very desirable:
        my ($foo_a) = @_; # Simple my $foo_a = shift; # Comparable my ($foo_a) = (shift); # Odd my ($foo_a, $foo_b) = @_; # Typical my ($foo_a, $foo_b) = (shift, shift); # Odder my ($foo_a, $foo_b, $foo_c, $foo_d) = @_; my ($foo_a, $foo_b, $foo_c, $foo_d) = (shift, shift, shift, shift);
        The last one is, I hope you'll agree, outrageous, and is best reserved for those sitations where you'd explain it, but it's a "long story".

        I'm not saying that you shouldn't use shift. You can program any way you like. You can also use goto with impunity, variable names that make no sense, and use substr and unpack instead of regular expressions. What I'm suggesting is that using multiple shifts in a function is poor form and is a bad habit to develop.

        Oh, and a goto by any other name still smells as rotten. I'd like to see any Benchmark that could show that using that technique you describe could provide measurable performance gains. As far as I can tell, passing the whole args array is fairly efficient. Pulling them apart and repacking them isn't.