http://qs321.pair.com?node_id=161476


in reply to Shift versus Sanity

Style, readability and maintainability are much more important in most cases. That's why I always assign @_ to a list of lexicals, unless I'm coding a one-liner. In classes for tie, I often use shift and pop in examples.

sub TIESCALAR { bless \(my $foo = pop), shift; } sub STORE { ${ +shift } = pop } sub FETCH { ${ +shift } } ### sub foo { my ($self, $foo) = @_; ... } sub foobar { my ($self, %options) = @_; ... }
If I use @_ and the sub is small (5 lines or less), I do shift the object and then use @_, because that saves me an array. Besides, sometimes you want to change the values, in which case you have to use @_.

Some examples of things that I do not like:
# Bad sub foo { my $self = shift; ... not using @_ anymore } sub bar { my $self = shift; my %options = @_; ... } # Worse sub foo { my $self = shift; my $foo = shift; my $bar = shift; ... } # Awful sub foo { my $self = shift; my $foo = shift; ... my $bar = shift; ... }
I dislike anything using more than one shift.

- Yes, I reinvent wheels.
- Spam: Visit eurotraQ.

Replies are listed 'Best First'.
Re: Re: Shift versus Sanity
by drewbie (Chaplain) on Apr 24, 2002 at 14:14 UTC
    # Bad sub bar { my $self = shift; my %options = @_; }
    I have to disagree with you on this one, sort of. I use this construct to set defaults to named parameters like this:
    sub bar { my $self = shift; my %options = (opt1=>'foo', # desc for opt1 opt2=>'bar', # desc for opt2 @_); }
    To me, this is the best of both worlds. I get an obvious object ($self), I know what my expected named arguments are, their default values, and a brief description of each parameter. Yes, it's slightly more memory intensive, but it's so much more intuitive to me that I'll take the tradeoff anyday.

    As someone else said, I'll take maintainability over a little verboseness & overhead anyday. Being able to figure out what the heck a rarely used option does is invaluable 4 months (or years!) down the road.

      I use this construct to set defaults to named parameters like this

      Oops, forgot about that idiom. Yes, when using to set defaults, it is okay :)

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.
      

Re: Re: Shift versus Sanity
by d_i_r_t_y (Monk) on Apr 25, 2002 at 08:34 UTC

    sorry juerd, can't agree. another common idiom that noone's mentioned is this:

    sub do_stuff { my $this = shift; my $session = shift || die "Missing req'd Session argument"; my $cgi = shift || new CGI (); ... }

    aesthetics aside, here are some hard figures on efficiency (slightly reformatted):

    [matt@dirty matt]$ ./test_arg_passing.pl Benchmark: timing 2000000 iterations of argumentative_1arg, argumentative_3args, direct_1arg, direct_3args, shifty_1arg, shifty_3args... argumentative_1arg: 17 wallclock secs (17.69 usr + 0.01 sys = 17.70 CPU) @ 112994.35/s (n=2000000) argumentative_3args: 21 wallclock secs (21.93 usr + 0.02 sys = 21.95 CPU) @ 91116.17/s (n=2000000) direct_1arg: 10 wallclock secs (10.86 usr + 0.04 sys = 10.90 CPU) @ 183486.24/s (n=2000000) direct_3args: 13 wallclock secs (12.24 usr + 0.02 sys = 12.26 CPU) @ 163132.14/s (n=2000000) shifty_1arg: 17 wallclock secs (18.07 usr + 0.03 sys = 18.10 CPU) @ 110497.24/s (n=2000000) shifty_3args: 23 wallclock secs (23.91 usr + 0.01 sys = 23.92 CPU) @ 83612.04/s (n=2000000) total: 42000000

    not much of a difference, though the triple shift example is a bit pathological. here's the code for the above:

    #!/usr/bin/perl -w use Benchmark; use strict; package ArgTest; sub shifty_1arg { my $this = shift; my $first_arg = shift; $$this += $first_arg; } sub shifty_3args { my $this = shift; my $first_arg = shift; my $second_arg = shift; my $third_arg = shift; $$this += $first_arg + $second_arg + $third_arg; } sub argumentative_1arg { my( $this, $first_arg ) = @_; $$this += $first_arg; } sub argumentative_3args { my( $this, $first_arg, $second_arg, $third_arg ) = @_; $$this += $first_arg + $second_arg + $third_arg; } sub direct_1arg { ${$_[0]} += $_[1]; } sub direct_3args { ${$_[0]} += $_[1] + $_[2] + $_[3]; } sub value { return ${$_[0]} } package main; my $total; bless( my $object = \$total, 'ArgTest' ); my @args = ( 1 .. 3 ); timethese( 2_000_000, { shifty_1arg => sub { $object->shifty_1arg( @args ) }, argumentative_1arg => sub { $object->argumentative_1arg( @args ) }, direct_1arg => sub { $object->direct_1arg( @args ) }, shifty_3args => sub { $object->shifty_3args( @args ) }, argumentative_3args => sub { $object->argumentative_3args( @args ) }, direct_3args => sub { $object->direct_3args( @args ) }, } ); print "total: " . $object->value . "\n";

    matt

      sub do_stuff { my $this = shift; my $session = shift || die "Missing req'd Session argument"; my $cgi = shift || new CGI (); ... }

      As said, I think that's horrible.

      sub do_stuff { my ($self, $session, $cgi) = @_; croak 'Session not optional' unless $session; $cgi ||= CGI->new(); ... }
      I call my objects $self, not $this. You can see the three arguments in a single line, instead of spread over three.

      esthetics aside, here are some hard figures on efficiency (slightly reformatted)

      I am starting to think that you didn't read my post, and are only commenting on the piece of code. Efficiency is important, but not more important than readability and maintainability. Whenever efficiency is important, you probably should not be using OO.

      - Yes, I reinvent wheels.
      - Spam: Visit eurotraQ.
      

        of course i read your post; the original post was about the efficiency of the various techniques! i generally prefer the shifting technique, perhaps cause my editor nicely syntax-colours the my's. 90% of the time it's purely aesthetics, though sometimes one method will lend itself to a particular technique; such as when the second or third argument is a (long) list or hash. TIMTOWTDI.

        besides, it's going to be a moot point in perl6; everything will be named in the method signature.

        but i agree. readability and maintainability are almost always preferable to 5% faster execution. there's no way i could hold a team of 6 and 100K lines of perl together if i didn't think so :-)