[tpm] Pub discussion (1)

Zoffix Znet zoffix at zoffix.com
Fri Aug 29 02:36:53 PDT 2008


Here are the "speed" results. The shift() is faster unless you are
shifting off 10 or more parameters. It's because my ( $x ) = @_; makes a
copy.:

Three parameters:
            Rate    @_ shift
@_     6633811/s    --  -70%
shift 22285677/s  236%    --

Ten parameters:
shift 1470972/s    --  -17%
@_    1772951/s   21%    --


But if you worry about speed on this level you should really be using a
different language.


Not sure why you list half of those things in "disadvantages". To me it
seems obvious that if the sub is supposed to modify passed arguments
those need to be writable. As long as this is documented let perl handle
the errors if the user of your sub passes incorrect arguments.

Personally, I stay far away from modifying aliased arguments. What I
find useful though is that you could check whether or not your sub was
called in void context (by using wantarray()) and if it was, modify
passed arguments in place.

By the way, instead of my ( $x, $y ) = ( shift, shift ); which was
proposed below, I'd use my ( $x, $y ) = splice @_, 0, 2; for the purpose
of removing those two arguments from @_ (same as shift does)

Cheers.




On Fri, 2008-08-29 at 04:55 -0400, Rob Janes wrote:
> I've heard that this:
> 
> 1. my ( $x, $y ) = @_;
> 
> is better than this:
> 
> 2. my ( $x, $y ) = ( shift, shift );
> 
> which is the same as:
> my $x = shift;
> my $y = shift;
> 
> The advantages:
> a. number 1 is faster (this is what I've heard.  Anybody profiled this?)
> b. number 1 leaves the aliased arguments still on the stack, available 
> to be modified if need be.
> 
> The disadvantages:
> a. if you want to assign to the alias, you have to leave it on the
>     stack (you can't shift it off), and assign to it via
>     $_[nnn] = "xoxoxox";
> b. if you want to assign to the alias, it has to be writable.  I
>     cannot be an alias to "1234 tell me what you're looking for"
>     (a string constant). Usually you'll get an error when you try to
>     assign.  Occasionally you'll get a core dump (unrecoverable
>     error in perl).  I forget the circumstances.  Something about
>     passing the alias to the read only to a core routine that
>     expects a writable.
> c. the parameter must be supplied (undef isn't writable)
> d. to be safe, declare your parameters like in sub x($$$@)
> e. to be even more safe, check the SvREADONLY flag on
>     the variable.  Use readonly() from Scalar::Util or Scalar::Readonly.
> 
> so, this is a possible usage:
> 
> use Scalar::Util qw(readonly);
> 
> ...
> 
> sub do_logging($$$$) {
>    my ( $self, $in_message, $out_result_code, $inout_filehandle ) = @_;
>    ## "$out_result_code" is just a place holder you can't use
>    ## the variable for it's purpose
> 
>    ...
>    ## let's say the logfile gets full, and we want to close and reopen
>    if ( !readonly( $_[3] ) ) {
>      if ( $rotate_logfile_now ) {
>        $inout_filehandle->close;
>        ## compress it?
>        $self->gen_new_logfile_name;
>        $inout_filehandle = $_[3] = new IO::File "> $$self{LOGFILE}";
>        ## of course, if you keep the LOGFILE name in $self, you could
>        ## keep the filehandle there too, but that would blow the
>        ## example
>      }
>    }
> 
>    ...
>    print $inout_filehandle "$level $timestamp $in_message\n"
>      if $inout_filehandle;
> 
>    ...
>    ## set to $out_result_code position
>    if ( !readonly($_[2]) ) {
>      if ( $problems ) {
>        $_[2] = [ 0, 'OK', 'No Problems' ];
>      } else {
>        $_[2] = 0;
>      }
>    }
> 
>    return $problems ? 0 : 1;
> }
> 
> It only really works for scalars, although the scalars can be objects or 
> references.  It could be a shared memory handle, or a message, or an 
> error trace stack.  And there's no reason you couldn't put those in a 
> $self, why have them on the parameter list?
> 
> http://search.cpan.org/~gbarr/Scalar-List-Utils-1.19/lib/Scalar/Util.pm
> http://search.cpan.org/~gozer/Scalar-Readonly-0.02/lib/Scalar/Readonly.pm
> http://search.cpan.org/~roode/Readonly-1.03/Readonly.pm
> http://search.cpan.org/~roode/Readonly-XS-1.04/XS.pm
> 
> Anyways, the filehandle example is kind of contrived.  If I want to do 
> something like that I put the filehandle in $self, not on the parameter 
> list.
> 
> I think a better scenario is where you want the subroutines or methods 
> to return a simple boolean for success or fail, and put more complex 
> diagnostics into a spot on @_.  Test if the spot is there and writeable 
> first.  If not, don't bother giving up more revealing diagnostics.
> 
> There's other cases where you can change the "parameters".  in foreach, 
> $_ will let you modify things in the foreach list.  In map, $_ is an 
> alias to the current item in the list, and it can be modified, changing 
> the item in the list.
> 
> -rob
> 
> Abram Hindle wrote:
> > I think you're totally correct. I think we were in the wrong here.
> > 
> > as this:
> > 
> > sub c {  "   lolcakes    whatwhat " }
> > c() =~ /([a-z]+)\s*([a-z]+)/g;
> > print "t1 ".t1($1,$2),$/;
> > c() =~ /([a-z]+)\s*([a-z]+)/g;
> > print "t2 ".t2($1,$2),$/;
> > c() =~ /([a-z]+)\s*([a-z]+)/g;
> > print "t3 ".t3($1,$2),$/;
> > c() =~ /([a-z]+)\s*([a-z]+)/g;
> > print "t4 ".t4($1,$2),$/;
> > 
> > sub t1 {
> > 	($a,$b) = @_;
> > 	warn "$a $b";
> > 	$b =~ /(a+)/;
> > 	return $a;
> > }
> > 
> > sub t2 {
> > 	$a = shift;
> > 	$b = shift;
> > 	warn "$a $b";
> > 	$b =~ /(a+)/;
> > 	return $a;
> > }
> > 
> > sub t3 {
> > 	$a = $_[0];
> > 	$b = $_[1];
> > 	warn "$a $b";
> > 	$b =~ /(a+)/;
> > 	return $a;
> > }
> > 
> > sub t4 {
> > 	warn "$_[0] $_[1]";
> > 	$_[1] =~ /(a+)/;
> > 	return $_[0];
> > }
> > 
> > produces this:
> > lolcakes whatwhat at ref.pl line 14.
> > t1 lolcakes
> > lolcakes whatwhat at ref.pl line 22.
> > t2 lolcakes
> > lolcakes whatwhat at ref.pl line 30.
> > t3 lolcakes
> > lolcakes whatwhat at ref.pl line 36.
> > t4 a
> > 
> > We were warning against using @_ directly
> > since it is aliased. If you look in the last example
> > $_[0] has changed.
> > 
> > And for review form perlsub:
> > 
> > Any arguments passed in show up in the array @_. Therefore, if you
> > called a function with two arguments, those would be stored in $_[0]
> > and $_[1]. The array @_ is a local array, but its elements are aliases
> > for the actual scalar parameters. In particular, if an element $_[0]
> > is updated, the corresponding argument is updated (or an error occurs
> > if it is not updatable). If an argument is an array or hash element
> > which did not exist when the function was called, that element is cre‐
> > ated only when (and if) it is modified or a reference to it is taken.
> > (Some earlier versions of Perl created the element whether or not the
> > element was assigned to.) Assigning to the whole array @_ removes that
> > aliasing, and does not update any arguments.
> > 
> > So we were wrong about case of using shift.
> > 
> > abram
> > 
> > 
> > Alex Beamish wrote:
> >> Greetings,
> >>
> >> After Madison's presentation on Net::DBus tonight, we retreated to
> >> Burgundy's where a number of interesting technical discussions popped
> >> up. Among them were discussions as to whether
> >>
> >>     my $self = shift;
> >>     my $value = shift;
> >>
> >> would mean changes to $self would be reflected the same way than if
> >> $self and $value were collected in one fell swoop using
> >>
> >>     my ( $self, $value ) = @_;
> >>
> >> My experiments consisted of three files, Obj1.pm:
> >>
> >> package Obj1;
> >>
> >> sub new
> >> {
> >>     my $class = shift;
> >>     my $self = {};
> >>
> >>     bless ( $self, $class );
> >>     return ( $self );
> >> }
> >>
> >> sub add
> >> {
> >>     my $self = shift;
> >>     my $value = shift;
> >>
> >>     $self->{value} = $value;
> >> }
> >>
> >> sub value
> >> {
> >>     my $self = shift;
> >>     return ( $self->{value} );
> >> }
> >>
> >> 1;
> >>
> >> And the almost identical Obj2.pm:
> >>
> >> package Obj2;
> >>
> >> sub new
> >> {
> >>     my $class = shift;
> >>     my $self = {};
> >>
> >>     bless ( $self, $class );
> >>     return ( $self );
> >> }
> >>
> >> sub add
> >> {
> >>     my ( $self, $value ) = @_;
> >>
> >>     $self->{value} = $value;
> >> }
> >>
> >> sub value
> >> {
> >>     my $self = shift;
> >>     return ( $self->{value} );
> >> }
> >>
> >> 1;
> >>
> >> And finally the test script:
> >>
> >> #!/usr/bin/perl -w
> >> #
> >> #  Test creating Obj1 and Obj2 to see if methods that access arguments
> >> #  differently affect whether changes propogate back to the caller.
> >> #  Specifically, does
> >> #
> >> #    my $self = shift;
> >> #    my ( $vars ) = @_;
> >> #
> >> #  produce a different result than
> >> #
> >> #    my ( $self, $vars ) = @_;
> >>
> >> use Obj1;
> >> use Obj2;
> >>
> >> {
> >>     my $obj1 = Obj1->new();
> >>     $obj1->add("This is object one");
> >>     print "Obj1 value is " . $obj1->value() . "\n";
> >>
> >>     my $obj2 = Obj2->new();
> >>     $obj2->add("This is object two");
> >>     print "Obj2 value is " . $obj2->value() . "\n";
> >> }
> >>
> >> The resulting output of running test12.pl is
> >>
> >> [alex at foo tpm-August2008]$ perl -w test12.pl
> >> Obj1 value is This is object one
> >> Obj2 value is This is object two
> >>
> >> This suggests that both methods (two shifts, or a single pull from @_)
> >> produce the same results.
> >>
> >> Have I misunderstood, or coded something incorrectly? I believe that
> >> both approaches mean pass by reference, meaning that changes are
> >> reflected.
> >>
> > 
> > 
> > 
> > ------------------------------------------------------------------------
> > 
> > _______________________________________________
> > toronto-pm mailing list
> > toronto-pm at pm.org
> > http://mail.pm.org/mailman/listinfo/toronto-pm
> 
> _______________________________________________
> toronto-pm mailing list
> toronto-pm at pm.org
> http://mail.pm.org/mailman/listinfo/toronto-pm



More information about the toronto-pm mailing list