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

After a bit of experimenting I came up with the following syntax:

my $label_colnum = &column_exists( \@data, $_[1] || 0 );

Basically the line reads: test that the 2nd param passed to this sub (or 0 if it is undef) column exists in @data; if so, take the returned result of &column_exists and set $label_colnum equal to it.

&column_exists tests to see if the passed column number exists in @data. If the column does exist, it returns back the same column number; if it fails, it returns back a -1.

My question: How can I set this line up to DIE (or call another sub) if the value returned by &column_exists is -1?

TIA

======================
Sean Shrum
http://www.shrum.net

Replies are listed 'Best First'.
Re: Passing / evaluating / dieing on one line...
by Sidhekin (Priest) on Apr 05, 2002 at 11:58 UTC

    Something like this, perhaps?

    (my $label_colnum = &column_exists( \@data, $_[1] || 0 )) == -1 and di +e;

    Note that you don't test for definedness with ||, but for truth -- so that "" || 0 is also 0. But you already knew that, right?

    The Sidhekin
    print "Just another Perl ${\(trickster and hacker)},"

Re: Passing / evaluating / dieing on one line...
by dragonchild (Archbishop) on Apr 05, 2002 at 14:42 UTC
    Before this goes any further, I'm going to throw cold water on this "one line" business.

    UNLESS YOU ARE WRITING THROW-AWAY CODE, SUCH AS AN OBFUSCATION OR GOLF, DO NOT TRY AND FIT EVERYTHING ON ONE LINE!

    Production code (i.e., anything that is used more than once) should be as readable and maintainable as possible. If this means you use 10 lines, then use 10 lines!

    (my $label_colnum = &column_exists( \@data, $_[1] || 0 )) == -1 and di +e;
    should really look something like
    my $second_value = defined $_[1] ? $_[1] : 0; my $label_column = &column_exists(\@data, $second_value); die if $label_column == -1;
    Obviously, you'd name $second_value to be something meaningful in your situation. In addition, you're putting on each line one distinct idea.
    1. Set up the second value in the function call.
    2. Do the function call and store the returned value somewhere.
    3. Make sure that the returned value is meaningful.
    Human time is the most expensive time in programming. Save human time and you'll be the more effective programmer.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Not if it will end up like this:

      (my $label_colnum = &column_exists( \@data, $_[1] || 0 )) == -1 and di +e; (my $key_colnum = &column_exists( \@data, $_[1] || 1 )) == -1 and di +e; (my $cross_colnum = &column_exists( \@data, $_[1] || 2 )) == -1 and di +e; # ...

      It's easier to cut-n-paste, it's obvious to a maintainer how to add another colnum variable.

      If you later want to refactor it's also easier to automate the conversion if the statements are grouped on one line. Simple s/blah (\w) blah (\d) blah die (".*");$/refactorsub(\1,\2,\3);/; or such, no multi-line wierdness ;).

      I tend to think of long identicalish lines as a template or macro or pseudo sub type of thing.

      Which would you prefer?

      do_A; do_B; do_C; do_D; do_A; do_B; do_C; do_E; do_A; do_B; do_C; do_C; or do_A; do_B; do_C; do_D; do_A; do_B; ...

      The yaddayaddayadda (...) is going to be one of my favorite operators in Perl 6 ;)

        Your example is spurious, because it's bad code.
        my %Columns = ( 'label' => 0, 'key' => 1, 'cross' => 2, ); foreach my $col_name (keys %Columns) { $Columns[$col_name} = column_exists( \@data, $_[1] || $Columns{$co +l_name} ); die if $Columns{$col_name} == -1; }
        Now, adding a new column is a matter of changing the %Columns hash. In addition, it's much easier to factor out the %Columns hash to some configuration file this way than doing it your way.

        In addition, this lends itself to even further improvements. For example, consider

        my %Columns = ( 'label' => { default => 0, exists => 0, }, 'key' => { default => 1, exists => 0, }, 'cross' => { default => 2, exists => 0, }, ); foreach my $col_name (keys %Columns) { $Columns[$col_name}{exists} = column_exists( \@data, $_[1] || $Columns{$col_name}{default} ) +; die if $Columns{$col_name}{exists} == -1; }

        THAT is self-documenting code!

        Furthermore, any time I see

        do_A; do_B; do_C; do_D; do_A; do_B; do_C; do_E; do_A; do_B; do_C; do_C;
        I was to do something like:
        for (\&do_D, \&do_E, \&do_C) { do_A; do_B; do_C; $_->(); }
        It's cleaner, more maintainable, and more extensible.

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Wow! What did I do? This node is mutating!

      I can see your point about human time...ultimately, the code is going into a library of subs I'm making and (most of the time) I will never need to look at the code again since I just need it to produce an end result.

      I wrote about 15 small, yet very specialized subs last night and after sleeping on it and coming back, I can see how doing everything step by step may make things easier to follow (and maybe even to code). Granted, in my defense, I'm REALLY BIG on code comments in everything I write so that helps. 8-)

      ======================
      Sean Shrum
      http://www.shrum.net

Re: Passing / evaluating / dieing on one line...
by talexb (Chancellor) on Apr 05, 2002 at 12:02 UTC
    Your question isn't that clear, but if you want column_exists to return a particular element, or the zeroth element if that element is undef, then you could write the following:
    sub column_exists { my ( $ArrayRef, $Column ) = @_; return ( $ArrayRef->[$Column] || $ArrayRef->[0] ); }
    If you want the calling code to die if the value is -1, the following will probably work:
    my $label_colnum = &column_exists( \@data, 1 ) if ( $label_colnum == -1 ) { die "Something bad!"; }

    --t. alex

    "Here's the chocolates, and here's the flowers. Now how 'bout it, widder hen, will ya marry me?" --Foghorn Leghorn

Re: Passing / evaluating / dieing on one line...
by kappa (Chaplain) on Apr 05, 2002 at 13:35 UTC
    What's wrong with:
    (my $label_colnum = &column_exists( \@data, $_[1] || 0 )) != -1 or die +;
      I don't believe that $_[1] is going to tell the routine column_exists to get the second element of @data -- it's going to pass the second element of $_, whatever that may be. It's a different context -- that's why my solution used 1 instead.

      Down in the subroutine, @{$_[0]}[1] will select the second element of the first parameter (as an array reference), which is close to $_[1] but still not the same thing.

      --t. alex

      "Here's the chocolates, and here's the flowers. Now how 'bout it, widder hen, will ya marry me?" --Foghorn Leghorn

      Somehow the desire to use $_[0] within routines (or anywhere, for that matter) has never tempted me. Why not just declare and use a my variable?