in reply to Re^6: Module Announcement: Perl-Critic-1.01 ("scalar")
in thread Module Announcement: Perl-Critic-1.01

Other than populating lists about to become hashes, what advantages do you find with the explicit return undef convention?

I wasn't trying to contradict you, play semantic games, nor make a silly argument. My concern was that your statements would mislead people with less understanding of the context issue.

Perhaps, I was too brief before, because

my %hash= ( key1 => genValue1(), key2 => genValue2() };

was an obviously made-up example and I didn't care to pick at it.

Why couldn't genValue1() generate a solitary first value or die and so conform to a bare return convention? Update: which is just to say either convention is workable; also key => val() || undef,

Be well,
rir

Replies are listed 'Best First'.
Re^8: Module Announcement: Perl-Critic-1.01 ("scalar")
by tye (Sage) on Jan 27, 2007 at 06:50 UTC
    Other than populating lists about to become hashes, what advantages do you find with the explicit return undef convention?

    I've already given other examples in this thread. In particular, passing arguments to functions and assigning values to a list of scalar variables.

    because [assigning a list to a hash] was an obviously made-up example and I didn't care to pick at it.

    Well, I don't often use "key1" as a key name nor name a function "genValue", but otherwise that code isn't an outlandish made-up example stretched beyond reason just to prove some point. It is an example of quite typical code that I chose exactly because I consider it quite typical, reasonable code that I've written often and see often. You never assign a list to a hash? Or do you never call functions when you do this? Perhaps you sometimes use "named arguments" to functions? That has identical problems.

    I don't know how to come up with examples that meet your expectations for being worth picking at if you can't tell me what is unreasonable about assigning a list to a hash (or passing (named or just positional) arguments to functions or assigning a list of scalar expressions to a list of scalar variables).

    You find val() || undef more readable / maintainable? We aren't talking about whether or not you can work around the over-use of return;, we are talking about whether it improves code in all cases. val() // undef would at least be closer in meaning to scalar val() but val() || undef assumes that all false values mean the same as undef. Just like it can be quite appropriate for "failure" to be returned as '' (as opposed to () or even explicit undef), it can be even more important for '' to be distinct from undef.

    Even push @results, doTask(); suffers if "failure" can only ever be the empty list. That'd have to be push @successes, doTask();.

    - tye        

      I don't have any significant disagreement since you modified your assertion that using bare returns is a bad practice. And thanks--I found your other examples after my post.

      Regarding:

         my %hash= ( key1 => genValue1(), key2 => genValue2() };

      I did not find assigning a list to a hash artificial; just the naming indicated a made-up example. I didn't mean to imply that your code is outlandish or stretched beyond reason. If I understood how I implied that, I would try to avoid doing so in the future.

      List to list assignments are expressive, but they can increase the complexity of error checking.

      The bare return convention can be seen as filling arrays without useless elements and as promoting early validation.

      I don't find your arguments about the convention breaking code convincing, because if the convention were in use the code would just be written differently. We are coming at this issue from very different places; I would not have said that I was talking about bare returns improving code in all cases. You are arguing from the bottom up, presuming the author's knowledge of what genValue1() can return; I see the value of these conventions in helping a reader to avoid the need to look up genValue1(). From that perspective, your example with scalar lc is beside the point because it is a builtin and so should be known.

      If I were running a large team and only one of these conventions was lintable, I would find lintability to be a compelling argument. The readability-in-the-small aspect becomes less significant.

      Be well,
      rir

      # bare return push @premiums, get_value( $_ ) for ( @xactions ); if ( @premiums ) { } # return undef for ( @xactions ) { push @premiums, defined( my $val=get_value($_) ? $val : (); } if ( @premiums ) { } ### # bare return my %hash; $hash{name} = get_name(); $hash{tag} = get_tag(); # return undef my %hash = ( name => get_name(), tag => get_tag() ); ### # bare return ( $second, $first ) = ( seconding(), firsting() ); if ( $first ) { } # return undef ( $first, $second ) = ( firsting(), seconding() ); if ( $first ) { }