Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Mr. Ternary is greater than Mrs. If Else

by PerlPhi (Sexton)
on May 19, 2007 at 17:02 UTC ( [id://616342]=perlquestion: print w/replies, xml ) Need Help??

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

hi,,, while ago i was wondering why do some programmers rarely uses the ternary operator. wherein it is less typing indeed. i believe in the classic virtue of Perl which is laziness. well let me show you something first before i go to my delimma.

codes as follows using Mrs. If Else:

#!perl/bin/perl use strict; print "Are you sure you want to quit ('yes' or any key for 'no'): "; chomp($_ = <STDIN>); if (/\byes\b/i) { print "Press any key to exit..."; <STDIN>; exit; } else { print "Thanks, you stayed... But then, goodbye.\n"; print "Press any key to proceed...\n"; <STDIN>; } print "GOOD DAY";

equivalent codes for Mr. Ternary as follows:

#!perl/bin/perl use strict; print "Are you sure you want to quit ('yes' or any key for 'no'): "; chomp($_ = <STDIN>); /\byes\b/i ? eval { print "Press any key to exit..."; <STDIN>; exit; } : eval { print "Thanks, you stayed... But then, goodbye.\n"; print "Press any key to proceed...\n"; <STDIN>; }; print "GOOD DAY";

Advantages of Mr. Ternary over Mrs. If Else:

1. shorter code

2. permits the parenthesis not to be used in the expression

3. permits the curly braces not to be used (well in here, eval takes its place. and note if you put an eval over Mrs. If Else, then Mr. Ternary is more appropriate)

4. promotes runtime error handling (the program doesn't exit so sudden)

5. the statements are more clearer to understand after a true or false evaluation

Disadvantages of Mr. Ternary:

1. difficulty in reading (only for the first timers because this is not conventional)

2. the return value of eval cannot be assigned to another variable (but there is the special variable $@ that holds it for you. you can evaluate that after the ternary operation)

3. tedious in bullet proofing a program (it is because you cannot quickly notice the runtime error inputted by the end user or file. in which Mr. Ternary uses the eval. it happens when your statements are so lenghty inside the eval block. but here is a solution for that, see next)

optional code revisions while bullet proofing:

#!perl/bin/perl use strict; print "Are you sure you want to quit ('yes' or any key for 'no'): "; chomp($_ = <STDIN>); /\byes\b/i ? \& { print "Press any key to exit..."; <STDIN>; exit; } : \& { print "Thanks, you stayed... But then, goodbye.\n"; print "Press any key to proceed...\n"; <STDIN>; }; print "GOOD DAY";

the only code was changed in here was "eval" to "\&"... now my delimma goes here... i don't know whats "\&" for. i just seen it on the Perl documentation under the strict pragma, and i read what it says "There is one exception to this rule...\& is allowed so that goto &$AUTOLOAD would not break under stricture.". well im just a novice programmer with Perl i don't really understand that. so what does "\&" mean?

back to Mr. Ternary, i think there is just only one slight drawback in using the ternary operator. that is difficulty in reading. but then its easy to overcome. so in other words Mr. Ternary is more handy than Mrs. If Else. so i think Mrs. If Else should be dropped from our system.

but then, if you have other downs in mind on Mr. Ternary, your statements will be gladly evaluated, then i will give you the output.

thanks in advance... keep deep and dark!

From: PerlPhi

Replies are listed 'Best First'.
Re: Mr. Ternary is greater than Mrs. If Else
by jZed (Prior) on May 19, 2007 at 17:20 UTC
    And don't forget Mr/Ms/Mrs transgendered Elsif. Mr. Ternary is often cleaner than Elsif:
    $x = ($d) ? do_one() : ($e) ? do_two() : ($f) ? do_three() : do_default() ;
Re: Mr. Ternary is greater than Mrs. If Else
by doom (Deacon) on May 19, 2007 at 17:29 UTC
    Ternaries have readability problems: that's enough to shoot them down right there. The small amount of brevity you gain with them just isn't worth it.

    Further, I'd claim that "if/else" constructs are eaisier to maintain, because if you need to check for another case later it's easy to stick in "elsif" clauses, but with ternaries you end up with "cascading ternaries", which strike me as even harder to read.

    Notably though, Conway in his "Best Practices" doesn't recommend against ternaries, instead he just recommends formatting cascading ternaries in columns to improve readability.

      yes, readability at first is a problem with Mr. Ternary... i can't get wrong with that... but as often you use the ternary operator becomes handy. but wait my delima was this "\&". what was that execption for in the strict pragma?
        yes, readability at first is a problem with Mr. Ternary... i can't get wrong with that... but as often you use the ternary operator becomes handy. but wait my delima was this "\&". what was that execption for in the strict pragma?

        I think it is your dilemma, and yes: I had never seen it. Indeed, had you asked me, I would have guessed it was no valid syntax at all. And while I'm far from being a guru myself, I've seen quite a lot of code over the years, from gurus too. However reasoning on it a little, it's easy to see it simply amounts to taking a real reference after taking a symbolic dereference. The exception perldoc strict talks about is that that particular symbolic dereference, in that situation, doesn't issue an error, while it would in all the other situations:

        C:\temp>perl -wMstrict -e "\&{'foo'}" Useless use of reference constructor in void context at -e line 1. C:\temp>perl -wMstrict -e "&{'foo'}" Can't use string ("foo") as a subroutine ref while "strict refs" in us +e at -e line 1.

        Why you think you can use that instead of eval is completely out of my comprehension. The semantics is completely different.

      well, overall its all about readability problems with Mr. Ternary...

      to easily remember the structure of Mr. Ternary a multi-decision structuring as follows:

      <expression> ? eval { <statement>; <statement>; <statement>; <expression> ? eval { <statement>; <statement>; <statement>; } : eval { <statement>; <statement>; <statement>; }; } : eval { <statement>; <statement>; <statement>; <expression> ? eval { <statement>; <statement>; <statement>; } : eval { <statement>; <statement>; <statement>; }; };

      NOTE: (eval or \& or do) well also work

      literally, Mr. Ternary is more on simple symbols that gives you a more concentration on expressions and statements without being bothered with words like if, elsif, and else.

      i don't think so that other languages could make Mr. Ternary more functional (making Mr. Ternary hold multiple-statements) than Perl could do. what do you think?

        This looks quite orderly, since the only words you are using here are 'eval', 'statement' and 'expression'. If you fill that with 'real code', the picture will get different, and the tiny ':' will get hard to spot at a glance.

        In contrast, 'if-elsif-else' statements stand out and are thus better readable on larger constructs.

        As for \& {}, that's an abuse of the coderef constructor and it will clutter up your symbol table.
        <expression> ? eval { <statement>; <statement>; <statement>; <expression> ? eval { <statement>; <statement>; <statement>; } : eval { <statement>; <statement>; <statement>; }; } : eval { <statement>; <statement>; <statement>; <expression> ? eval { <statement>; <statement>; <statement>; } : eval { <statement>; <statement>; <statement>; }; };
        if (<expression>) { <statement>; <statement>; <statement>; if (<expression>) { <statement>; <statement>; <statement>; } else { <statement>; <statement>; <statement>; } } else { <statement>; <statement>; <statement>; if (<expression>) { <statement>; <statement>; <statement>; } else { <statement>; <statement>; <statement>; } }

        What do you do with your large ?: construct if you have by chance to insert a third condition (a.k.a elsif) statement? Which of both columns is better readable? Can you tell at a glance if there's a semicolon missing (or one that causes a syntax error) on a line in the left column?

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        literally, Mr. Ternary is more on simple symbols that gives you a more concentration on expressions and statements without being bothered with words like if, elsif, and else.

        Indeed: if, else, elsif are flow control constructs. ?: is an operator. Now, it happens, thanks to short circuiting and the availability of constructs that take a block and execute it, that the latter can be used in a semantically equivalent manner to the former. Yet, as has been repeatedly explained to you in this thread, they serve different purposes: there are superimpositions and there may be some situation in which the choice is not obvious. But this is generally not the case.

        i don't think so that other languages could make Mr. Ternary more functional (making Mr. Ternary hold multiple-statements) than Perl could do. what do you think?

        I don't understand your question, but I'll make some guess and try to answer anyway: in some functional languages, the regular branching control structures behave much like (C and) Perl's ?: in that they return a value - exactly because they're functional. But seriously, your insisting on this issue makes me think that you're simply fond of the extreme conciseness you get out of it. OTOH several different monks already explained to you the reason why we generally do not strive for extreme conciseness: Perl has already a wrongly deserved bad name for being mostly line-noise, in some circles and speaking of other languages if I were to write programs that look like brainfuck I would... program in brainfuck! But then joy the world: Perl 6 will have a grammar modifiable at runtime, so you will be free to happily brainfuck it!

Re: Mr. Ternary is greater than Mrs. If Else
by shmem (Chancellor) on May 19, 2007 at 18:34 UTC
    Don't you dare to sow strife between Mrs. If Else and Mr. Ternary!

    They've lived together a couple of years now, and I will not let you induce quarrel amongst them over 'who is greater'!

    Both serve different purposes. Mrs. If Else provides for blocks of code to be executed conditionally, whereas Mr. Ternary shortcuts them with a single statement (if they resolve to simple expressions) or delegates them elsewhere (probably to Mrs. If Else again, appearing in some sub).

    They often interchange tasks, as most mordern couples do; but mostly Mr. Ternary likes to prepare hesh bugs while Mrs. If Else studies blocks of stock exchange charts to see what's best.

    I'd rewrite your Mr. Ternary code like this

    #!perl/bin/perl use strict; print "Are you sure you want to quit ('yes' or any key for 'no'): "; chomp($_ = <STDIN>); print /\byes\b/i ? <<LEAVE : <<STAY; Press any key to exit... LEAVE Thanks, you stayed... But then, goodbye. Press any key to proceed... STAY <STDIN>; print "GOOD DAY\n";

    to better show where Mr. Ternary shines - inlining a decision.

    Now, to your delimma (++ alone for mispelling dilemma twice in one post :-):

    In the expression

    $foo = 1; $foo ? \& { print "foo"} : \& { print "bar"};

    The ampersand & marks the following { } construct as a code block; the backslash disambiguates that operation from binary '&' (the bitwise AND) and returns a reference for that code block. Last, Mr. Ternary happily evaluates those references based on the 'truthness' of $foo. This is, at least, my interpretation of things, but I might be wrong. I never used that construct before...

    update And I am wrong! See betterworld's comment below.

    Nice post!

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      The ampersand & marks the following { } construct as a code block; the backslash disambiguates that operation from binary '&' (the bitwise AND) and returns a reference for that code block.

      It's not really a code block. \&{foo} is a reference to the subroutine with the name "foo". Similarly, \& { print "foo" } is a reference to the subroutine with the name that is returned by print, i. e. it's \&1 (unless print fails).

      $ perl -lwe 'my $code = \&{print "foo"}' foo $ perl -lwe 'my $code = \&{print "foo"}; $code->()' foo Undefined subroutine &main::1 called at -e line 1.

      (Note that $code is not called/dereferenced in the first one-liner, yet it prints foo.

        It's not really a code block. \&{foo} is a reference to the subroutine with the name "foo". Similarly, \& { print "foo" } is a reference to the subroutine with the name that is returned by print, i. e. it's \&1 (unless print fails).

        Well, there's a subtle difference. When you write &{foo} -with no quotes within the curlies-, that's (almost) just as if you had written &foo. This is not specific of subs, but of quite about all kind of variables:

        spock:~ [16:02:30]$ perl -wMstrict -le 'my $x=1; print ${x}' Ambiguous use of ${x} resolved to $x at -e line 1. 1 spock:~ [16:02:36]$ perl -wMstrict -le 'my $x=1; print ${"x"}' Can't use string ("x") as a SCALAR ref while "strict refs" in use at - +e line 1.
Re: Mr. Ternary is greater than Mrs. If Else
by blazar (Canon) on May 19, 2007 at 17:41 UTC
    hi,,, while ago i was wondering why do some programmers rarely uses the ternary operator. wherein it is less typing indeed. i believe in the classic virtue of Perl which is laziness.

    I believe in that virtue too. Though the answer is the usual one: we aim for the right™ amount of conciseness, not for maximum one - except in golf that is. The ternary operator is good for what it's good for: simple branching with simple expressions, and returning a value. That it can also be used as a general purpose branching construct is a whole another matter. In particular your use of block eval's (or do's) smells mostly like a dirty hack to me. Moreover, while I often happen to use if conditions, I find that they rarely have an else block too, let alone elseif ones, courtesy of all the early loop, sub and program exit facilities available.

Re: Mr. Ternary is greater than Mrs. If Else
by tilly (Archbishop) on May 20, 2007 at 23:24 UTC
    Short answer, because some programmers understand enough to be more concerned with maintainability than cleverness.

    First of all your overuse of eval has just killed your exception reporting unless you put in a check for $@ or die. (Which your code examples didn't.) By the time you've added that, you've just made your code longer and more obscure than the original if/else construct would have. (As several have noted, you could solve that problem by using do.)

    Secondly there is great value in having code with recognizable intent. For most use cases, ternary operations do not communicate intent as well as the traditional if/else. And this is not just a familiarity issue. An important principle is to put the most significant thought in the line of code first because that is what you'll notice when you're scanning through it. When you're scanning code, one of the most significant things to be aware of is the flow of control. The fact that the flow branches at an if statement is a critical fact, so you should start your line of code by communicating that fact clearly. Ternary statements don't do that, they bury the control of flow into easily missed punctuation. Occasionally this choice of emphasis is appropriate, but usually it is not.

    Thirdly, it is important for programmers to work well with others. An idiosyncratic coding style is a barrier for others who want to work with you. Sure, people's styles vary. But you had better have a very good reason to pick a style that nobody else uses. And your reasons for doing that are frankly not good enough.

    And finally, good programmers have to program in many different languages over the course of their careers. It is therefore wise to at least think about how well your style will work in many different languages. And the truth is that if/else style coding works appropriately in more languages than ternary operations do. Which is a reason why it is wise to use if/else whenever appropriate.

Re: Mr. Ternary is greater than Mrs. If Else
by tinita (Parson) on May 20, 2007 at 11:00 UTC
    maybe i missed the point of the question - but why didn't you just use do()?
    /\byes\b/i ? do { ... } : do { ... }
      maybe i missed the point of the question - but why didn't you just use do()?

      Are you suggesting another way to commit the crime? Well, after all I had already suggested it myself... ;-)

Re: Mr. Ternary is greater than Mrs. If Else
by Moron (Curate) on May 21, 2007 at 10:24 UTC
    It seems to me that the strict refs section of the manual has gone a bit wonky. To understand all this now needs a bit of history.

    Once upon a time there were compiled languages whereby subroutine parameters and indeed data referenced in the same scope could be passed around by a number of different ways: by name, by reference, by value, by descriptor being the four I know about. In a compiled language, passing by reference means simply by address instead of immediate value.

    Perl has facilities for mimicking these mechanisms which I won't go into for all cases ... oh what the hell ... here goes:

    by name: e.g. passing "fred" for access to $fred. This extends to anything passed literally, i.e. if you pass an expression by name, it is passed without evaluation for evaluation by whatever picks it up whereas by value it is first evaluated and then that value is passed.

    by reference: this time there is no address because Perl is not a compiled language, so a Perl reference is the key in the *symbol table (see under though about Perl implementation).

    by value: same as for compiled languages except that @_ is used instead of a system stack (or argument block for the case of Fortran) to pass parameters to subroutines.

    by descriptor: a string descriptor for a compiled language is the starting address of two memory locations where one contained the length and the other the starting address of the string. Perl very probably uses string descriptors internally, but provides programmer access to them via the symbol table to get the string value and a length function to get at the length directly. Similarly, compiled languages sometimes have array descriptors but whereas Perl might probably uses them internally, access to them for Perl programmers is provided via the symbol table - the length of the array is in this case also symbolically accessed for Perl.

    Compiled languages also use a code reference mechanism that Perl has mimicked - for compiled languages these are resolved into memory addresses by the linker - a linker takes chunks of ("object" machine) code that have symbolic references to each other and builds an image for loading whereby all the references (everything in the symbol table in fact) are resolved into relative addresses. The Perl interpreter does not do any linking but maintains code references in the (runtime) symbol table (update: compiled languages do not retain the symbol table at runtime unless a special debugging version is being compiled and linked).

    Therefore ALL Perl references are "symbolic" which is a rather glib shorthand for "are maintained in the symbol table rather than using addresses in memory as references". (Update: but not all symbolic references are by name :))

    (* It might be in terms of Perl implementation that there is a different symbol table implementation for different "types" - one for named and one for anonymous (in implementation, still having an internal id such as HASH + id), but however it might be split up, the collection of such implementations whether in separate structures or not is technically still "the symbol table" as far as Perl programmers can be concerned.)

    If the manual were amended to (updated for readability):

    "strict refs

    "This generates a runtime error if you use symbolic named references (see perlref)."

    update: perlref also needs to explain more clearly the distinction between named and anonymous symbolic references

    Then the examples and the exception suddenly would make sense when related to the amended rule...

    "There is one exception to this rule: $bar = \&{'foo'}; &$bar;is allowed so that goto &$AUTOLOAD would not break under stricture."

    breaking this into pieces ... \& means taking a code reference but to get a code reference for 'foo' requires look-up by name in the symbol table. So a special exception has been made to allow named access to the symbol table even when strict refs is in force - get the rule right and at last we can see what the use of the word "exception" is all about.

    __________________________________________________________________________________

    Update: I would say, however, that the OP example isn't doing anything with the code references and can dispense with them. The OP example also isn't doing anything with what the terniary operator returns, so making a code reference of it doesn't do anything either and if-else is indicated. An example of where the terniary operator is indicated:

    my $batchsize = @ARGV && ( $ARGV[0] =~ /^-b(\d+)/ ) ? $1 : 1000;
    Here the terniary operator prevents having separate assignments which would mean also having to declare the scalar separately from the assignments, making the terniary the more practical choice.
    __________________________________________________________________________________

    ^M Free your mind!

Re: Mr. Ternary is greater than Mrs. If Else
by Anonymous Monk on May 22, 2007 at 15:18 UTC
    I generally use it in-line in cases like this:
    printf("The answer is %s\n", defined($ans) ? $ans : "unknown");'
    
    or
    
    $ans = defined($ans) ? $ans : "unknown";
    
    
    This is left over from C programming days. I stopped at the first known construct. It seems efficient versus this:
    printf("The answer is ");
    if (defined($ans))
    {
        printf("%s\n", $ans);
    }
    else
    {
        printf("unknown\n");
    }
    
    I would not have a tendency to use it on multi-line constructs as shown in other examples in this thread because the ? and : tend to get lost.
Re: Mr. Ternary is greater than Mrs. If Else
by herby1620 (Monk) on May 21, 2007 at 20:55 UTC
    Long ago, in a galaxy far far away there was a language called Algol. It had various incantations, one of which was called "Algol 60" (I use that reference since I am a bit familiar with it). In Algol 60, you only had ONE way to do it.
    ... a := if b then c else d;
    Was a very acceptable construct. A few years later when the R of K & R was designing his language called "C", he liked this construct, but didn't like all the typing, and invented "Mr. Ternary". He already had control constructs from other languages (Mrs. IfElse) because they were very common. To combine the two into one wasn't his "style". So we were given two different constructs, one to use in control flow, and another one to use in expressions.

    Now along comes Mr. Wall and he desires to have something that will fit his acronym for the language he is calling Perl. That begat "eval" to make expressions out of control structures. So, we can now do everything any which way we desire to make wonderful artwork out of programs that are cryptic to all.

    Now comes our modern friend and he desires to keep his job (for whatever reason) and wants to do either of two things:

    1) Be as cryptic as possible so he will be "indispensable" guaranteeing full employment.

    2) Document all his code and make it as easy to read so he can be promoted to manager to earn more $$$.

    One can do almost anything more than one way. Typically one will be "better" for the given circumstances. You will need to decide which is which. It is up to you.

Re: Mr. Ternary is greater than Mrs. If Else
by ash (Monk) on May 22, 2007 at 13:55 UTC
    hi,,, while ago i was wondering why do some programmers rarely uses the ternary operator. wherein it is less typing indeed. i believe in the classic virtue of Perl which is laziness. well let me show you something first before i go to my delimma.

    I don't think the laziness virtue of Perl extends to sacrificing readability by saving to write a few characters...
    I like to be able to rest my eyes on the code, without getting dizzy. ;)

    -- 
    asksh <ask@0x61736b.net>

      I don't think the laziness virtue of Perl extends to sacrificing readability by saving to write a few characters...
      I like to be able to rest my eyes on the code, without getting dizzy. ;)

      I second that. In fact IMHO lazyness alone is not really a virtue. I know, because I'm so lazy!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://616342]
Approved by Joost
Front-paged by blazar
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2024-04-19 03:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found