http://www.perlmonks.org?node_id=654869

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

This is one of those things on which it is quite hard to find any good docs.

How does this formatting / style look? Is it readable enough?

Also, is it a bad thing to throw an exception in a ternary like that?

I'm trying to incorporate advice from Damian Conway's PBP, but did I succeed?

sub xyz { my ($ttt, $xxx, $yyy) = @_ == 2 ? (undef, @_) : @_ == 3 ? @_ : croak('Not good.') ;

Thanks, much.

  • Comment on Format / Logical Expression / Style Opinions: my, ternary, subroutine, @_
  • Download Code

Replies are listed 'Best First'.
Re: Format Style Opinions: my, ternary, subroutine
by gamache (Friar) on Dec 04, 2007 at 17:35 UTC
    I know Damian Conway gives this advice on PBP page 31, but he still can't make me like nested ternaries. If you're going to use his style, I suggest lining up the croak with the (undef, @_) and @_. Your code is readable, in any case.

    It is considered bad form to use a ternary structure to do things other than return a single value, in general, but I don't mind your use of croak as the "if all else fails" condition. (Update: I later saw this in PBP as well, on page 258 to be exact.)

Re: Format Style Opinions: my, ternary, subroutine
by friedo (Prior) on Dec 04, 2007 at 18:16 UTC

    I find it almost completely unreadable, and disagree vehemently with PBP's suggestion that nested ternaries are anything other than a horrible idea.

    I can think of no good reason why this simple functionality should be written so tersely, when a more sensible approach takes up almost the same amount of space.

    sub xyz { my ( $ttt, $xxx, $yyy ); ( $xxx, $yyy ) = @_ if @_ == 2; ( $ttt, $xxx, $yyy ) = @_ if @_ == 3; croak 'Not good' unless $xxx and $yyy; }

    As a tangent, I'd also consider thinking about why you have a sub where the first parameter is optional -- it's a lot easier if optional parameters go on the end.

      friedo wrote:
      > ...consider thinking about why you have a sub where the first parameter is optional...

      Because it is a wrapper for a command. Suppose the command was ls. It would be convenient to call the sub, thus:

      ls('-lrt', '/home');

      Does this convenience not outweigh breaking from the convention that optional args go last?

        My first thought is "If it's good enough for system, it's good enough for me"

        $ perl -e 'system("ls", "/home/brian");' # ... my stuff $ perl -e 'system("ls", "-lrt", "/home/brian");' # ... my stuff
Re: Format / Logical Expression / Style Opinions: my, ternary, subroutine, @_
by BrowserUk (Patriarch) on Dec 04, 2007 at 18:55 UTC
Re: Format Style Opinions: my, ternary, subroutine
by webfiend (Vicar) on Dec 04, 2007 at 18:11 UTC

    I no longer fear the ternary operator, so this is readable enough. There must be a clearer way to express the logic, though. Having the first parameter be undefined when @_ isn't quite long enough, and croaking if @_ isn't exactly the right length ... it makes my brain hurt a little.

    What about switching around the order of the parameters?

    sub xyz { my ($xxx, $yyy, $ttt) = @_; # You could also say -> if( !$xxx || !$yyy ) # if you wanted to avoid 'unless' like the PBB says unless ($xxx && $yyy) { croak('Not good.'); } # ... }

    This way we don't have to enforce a specific size for @_, too. Double bonus.

      Wow. That is a simpler way to express it. Thanks. I think I'm still in that "everything is a nail" phase with the ternary op.

      However, I don't think it is wise to quietly keep going if a 4th argument is passed to it. I don't know about anyone else who might use this sub, but I certainly want to tell myself if I'm using it wrong.

        I understand your nervousness about extra arguments, but I've learned that they don't really matter in Perl. An analogy that comes to mind is filling a glass of water. If I hand you a cup and you pour a gallon of water into it, all I get back is a cup. I might make fun of you for being so sloppy, but who cares? After all, I have the cup of water that I wanted.

        Still, if it is important to you, you can enforce it with logic in your sub.

        sub xyz { my $xxx = shift || croak('Missing xxx parameter'); my $yyy = shift || croak('Missing yyy parameter'); my $ttt = shift; # Enforce length of function parameter list. if (@_) { croak('Too many args for xyz!'); } # ... }

        ... but things like that risk making the code a little harder to read.

Re: Format / Logical Expression / Style Opinions: my, ternary, subroutine, @_
by GrandFather (Saint) on Dec 04, 2007 at 20:03 UTC

    A better question than "Is it readable enough?" is: "Is it as comprehensible as it can be?". BrowserUK's reply answers the comprehension question very well with a resounding "No!" for the nested ternary in this case.

    Although I'm somewhat partial to using the ternary operator, in most places an if is more readable. Almost always there are better alternatives to nested ternary operators. A little thinking outside the box (in this case "init from args first") can pay huge dividends.


    Perl is environmentally friendly - it saves trees
Re: Format Style Opinions: my, ternary, subroutine
by Sixtease (Friar) on Dec 04, 2007 at 17:33 UTC
    It's very well readable to me. I see no problem in that.
    use strict; use warnings; print "Just Another Perl Hacker\n";
Re: Format Style Opinions: my, ternary, subroutine
by moritz (Cardinal) on Dec 04, 2007 at 17:33 UTC
    I think it's quite readable, but probably you'll get as many different answers as monks care to answer ;-)

    If the conditions have different length, be sure th align the ? to the same column.

    Of course the croak text isn't optimal, but I guess that just serves as an example in your case.