in reply to Very very small style question

Well, I'd probably help my user by catching some coding mistakes rather than letting them cause strange behavior that they'd have to spend much more time debugging:

sub method { my $self= shift(@_); croak 'Usage: $oldVal= $obj->method( $idx [, $newVal ] )',$/ unless 1 <= @_ && @_ <= 2; my $i= shift(@_); my $old= $self->{B}[$i]; $self->{B}[$i]= shift(@_) if @_; return $old; }
But I don't like the magic numbers there so I might avoid them at the cost of some duplication but with even better error messages:
sub method { my $self= shift(@_); croak 'Missing $idx; usage: $oldVal= $obj->method( $idx [, $newVal + ] )',$/ unless @_; my $i= shift(@_); my $old= $self->{B}[$i]; $self->{B}[$i]= shift(@_) if @_; croak 'Too many args; usage: $oldVal= $obj->method( $idx [, $newVa +l ] )',$/ if @_; return $old; }
Then you can remove some duplication with:
{ my $usage; BEGIN { $usage= '$oldVal= $obj->method( $idx [, $newVal ] )' } sub method { my $self= shift(@_); croak "Missing \$idx; usage: $usage\n" unless @_; my $i= shift(@_); my $old= $self->{B}[$i]; $self->{B}[$i]= shift(@_) if @_; croak "Too many args; usage: $usage\n" if @_; return $old; } }

        - tye (but my friends call me "Tye")

Replies are listed 'Best First'.
Re: (tye)Re: Very very small style question
by MeowChow (Vicar) on Dec 19, 2000 at 00:06 UTC
    Why, in your last suggestion, do you use a BEGIN block? Are there any circumstances where $usage would not be set if you hadn't placed the assignment to it in a BEGIN block?

      I always assume that subroutines will be put into a scope where they will be compiled and never run [ that is, the subroutine will probably be called, but the lines around the subroutine will never be run ].

      If you don't use the BEGIN, then you have a race condition because the subroutine exists and can be called as soon as it is compiled but its "static variable" (will be declared but) won't be initialized until that line gets run, which could happen much later or not at all.

      I first ran into this problem with some border cases of using modules. The one that I remember was having two modules that depend on each other. Perl actually manages to get this mostly right (doing better than I would have thought was even possible). But the effect is that if A.pm uses B.pm which uses A.pm, then either A::import() or B::import() will be called before the code for that module gets run. I recall finding another case that was less easy to justify ignoring, but I don't remember the specifics right now.

      Another case is self-inflicted. I hate having to read "between" a huge list of subroutine declarations looking for the run-time statements so I force my top-level run-time code into sub main and enforce this discipline by ending my global declarations with:

      exit( main( @ARGV ) );
      (see (tye)Re: Stupid question for other self-inflicted discipline).

      So I guess that boils down to "No, I don't have any glaring, screaming, obvious cases that make not doing this a really, really bad idea." (: It is a personal coding habit that has saved me time more than once. It avoids a race condition, which is usually a good thing.

              - tye (but my friends call me "Tye")