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

This code is largely obsoleted by the development of Quantum::Superpositions, but I can't really justify roping in another module for the project I am doing.

I want to be able to ensure a set of variables will all have values before assigning them to @_

The following code works, but I would like

  1. for such code work under strict refs.
  2. to eliminate the need to have to "my" my variables and then re-list them in @word... anytime that something is repeated in a program, this is a warning flag that either you haven't abstracted things properly or the language does not allow for such abstraction.
use strict; sub file_name { my ($client_number, $MM, $DD, $S); my @word = qw($client_number, $MM, $DD, $S); no strict 'refs'; !defined($_[$_]) and die "$word[$_] not defined" or ${$word[$_]} = $_[$_] for (0..$#_); "I$client_number$MM$DD$S"; } file_name 1,2,3,4;
  • Comment on Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
  • Download Code

Replies are listed 'Best First'.
Re: Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
by japhy (Canon) on Nov 29, 2000 at 20:21 UTC
    How do you like this approach:
    sub someFunc { my @args = qw( client_number MM DD S ); # no commas here for (@args) { $_ = defined($_[0]) ? shift : die "$_ not defined"; } # hooray }
    Hey, you could even use a pseudohash so you can use the names instead of indices:
    sub someFunc { my $args = [ { client_number => 1, MM => 2, DD => 3, S => 4, }, ]; for (keys %$args) { my $idx = $args->[0]{$_} - 1; if (defined $_[$idx]) { $args->{$_} = $_[$idx], next } die "$_ not defined"; } # hooray }


    japhy -- Perl and Regex Hacker
      If you don't mind changing the calling conventions of your subroutine, go a step further and use named arguments in the form of a hash:
      sub someFunc { my %args = @_; my @arglist = qw{ client_number MM DD S }; foreach (@arglist) { die "$_ not given" unless exists $args{$_}; } # Now use $args{client_number} and $args{MM} }
Re: Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
by chipmunk (Parson) on Nov 29, 2000 at 20:41 UTC
    Have you considered using a hash? This code meets both of your stated requirements:
    sub file_name { my %args; @args{qw/client_number MM DD S/} = @_; for (keys %args) { defined($args{$_}) or die "\$$_ not defined"; } local $"; "I@args{qw/client_number MM DD S/}"; }
    You could even put the for loop in a separate subroutine and call it from all your subroutines where you want to verify the arguments.
Re: Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
by davorg (Chancellor) on Nov 29, 2000 at 20:20 UTC

    I want to be able to ensure a set of variables will all have values before assigning them to @_

    But that's not what you're doing here. You're checking that the values in @_ are defined before assigning them to your local variables using a horribly complex statement.

    Do you have to know the variable name? Wouldn't the parameter number be enough to track down any problems? I'd probably wrtie it something like this:

    use strict; sub file_name { die "incorrect number of parameters\n" unless @_ == 4; for each (0 .. $#_) { die "invalid parameter [$_]\n" unless defined $_[$_]; $" = ''; "I@_"' }

    Oh, and the commas in your qw are probably a bug too.

    --
    <http://www.dave.org.uk>

    "Perl makes the fun jobs fun
    and the boring jobs bearable" - me

      Wouldn't the parameter number be enough to track down any problems?

      Well, if instead of passing in a list of constants, he might well be passing in enough arguments, but one of them have a value of undef (which, of course, the second bit of your code would catch).

      Seems to me wanting the name of the invalid variable is one more step in princepawn's "the secretary should be able to use the program" ethic. Whether or not we agree with that aim is another matter =)

      Philosophy can be made out of anything. Or less -- Jerry A. Fodor

Re: Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
by arturo (Vicar) on Nov 29, 2000 at 20:16 UTC

    Why not go the following route?

    sub file_name { my ($client_number, $MM, $DD, $S) = @_; my @varnames = qw($client_number $MM $DD $S); for (my $i=0; $i <= scalar @_; $i++) { die "$varnames[$i] not defined\n" unless defined($_[$i]); } "I$client_number$MM$DD$S"; }

    Philosophy can be made out of anything. Or less -- Jerry A. Fodor

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re (tilly) 1: Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
by tilly (Archbishop) on Nov 29, 2000 at 20:37 UTC
    Statement number 2 reminds me of why I wrote Re (tilly) 1: Topics in Perl Programming: Table-Mutation Tolerant Database Fetches with DBI. Do you understand that not all abstractions are good? And some types of repetition really do buy you something?

    The task itself does not seem to me to be particularly important. Personally I would take a hint from the fact that you felt a need for symbolic refs, apply the usual fix and put your variables in a hash.

    *shrug*

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Maintaining strict refs while Binding a set of variables to @_ or dying if they are not defined
by princepawn (Parson) on Nov 29, 2000 at 20:40 UTC
    japhy, your code is close, but will not run under use strict. I have modified your example, but again I don't see a way of getting this to work under use strict.

    use strict; sub file_name { no strict 'vars'; no strict 'refs'; my @arg = qw(client_number MM DD S); for (@arg) { $$_ = defined($_[0]) ? shift : die "$_ not defined" } "I$client_number$MM$DD$S" } my $out = file_name 1,2,3,4; warn $out;

    But of course it can be improved with davorg's wonderful embellishment:

    { local $" "I@_" }

    This code reminds me of learning shorthand.

      Using davorg's little quoting nice-ness with a bit of finessing, we get:
      sub someFunc { my $i; local $"; for (qw( this that otherfield )) { die "$_ is undef" unless defined $_[$i++]; } "@_"; }


      japhy -- Perl and Regex Hacker
      It'd be easier if you reply to my message, so I don't have to search for a response. ;)

      Anyway, this code works for me:
      #!/usr/bin/perl -w use strict; sub someFunc { my $args = [ { client_number => 1, MM => 2, DD => 3, S => 4, }, ]; for (keys %$args) { my $idx = $args->[0]{$_} - 1; if (defined $_[$idx]) { $args->{$_} = $_[$idx], next } die "$_ not defined"; } print "@$args\n"; } someFunc(1,2,3,4); # fine someFunc(1,2,3); # 'S' is not defined
      It works under strict.

      japhy -- Perl and Regex Hacker