Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked

Re: Two simple code style advice questions (tye)

by tye (Sage)
on Jan 18, 2013 at 04:56 UTC ( #1013951=note: print w/replies, xml ) Need Help??

in reply to Two simple code style advice questions

I'd use 1b, in part because it is an important idiom. On a single line is even better. 1a is okay (the one advantage I'll grant it is that it avoids repeating either variable name -- I'm not sure why I've long used this only grudgingly). But if I wanted to go for maximum clarity, IMHO, I'd instead do:

my %ntests; $ntests{$_} = 0 for @tests;

Then there is:

@{ \my %ntests }{ @tests } = (0)x@tests; # :)

2a is pretty darn hackish and not something I'd expect to see in professional code. But I've come to find ternaries to often be less quick/easy to read than something like:

my $mol = ''; $mol = 'forty two' if 42 == $n;

Despite being 3 lines instead of 1, I find it significantly easier and faster to parse the intent. I especially don't like how the default value is almost lost in the single-line ternary. But I'd probably feel I was being a bit extravagant and then just use the 1-line ternary if the names and values are actually that short. For more and/or longer expressions, I'd format it more like:

my $mol = ! defined $n ? 'n/a' : 42 == $n ? 'forty two' : '';

(If I didn't use multiple "assignment \n\t if ...;" statements.)

- tye        

Replies are listed 'Best First'.
Re^2: Two simple code style advice questions (tye)
by BrowserUk (Pope) on Jan 18, 2013 at 05:23 UTC
    I find it significantly easier and faster to parse the intent.

    Could you quantify (in some fashion) what you mean by "significantly easier and faster"?

    my $mol = ( $n == 42 ) ? 'forty two' : '';
    my $mol = ''; $mol = 'forty two' if 42 == $n;

    I find your version quite horrible to parse.

    • Is that one statement or three?

      Oh! It's two!

    • And why is it (are they) all squished up like that?

      It looks like the the code-wrap routine has been given some ridiculously narrow width limit.

    • Why is he comparing a literal against a variable?

      Is the literal's value likely to suddenly change?

      (Yes. I am aware of the justifiction for the backward logic. :)

    As for your last example, I find it almost incredulous that you would code that; and almost impossible to parse without reformatting it.

    Why not just:

    my $mol = defined $n ? ( $n == 42 ? 'fourty two' : '' ) : 'n/a';

    I also find the concentration on the minutia of single statements far less important than the overall flow of the code.

    That is, when scanning the code, I only need to recognise that $mol has been initialised, and then the next step and the next. I'll only be concerned with what it was initialised to once I understand the overall flow; and if I suspect that might be the source of the problem I'm looking for, or otherwise needs closer inspection.

    I don't need to know all the details of each line (or 3 lines!) of code from an instantaneous glance. If I have to read the line twice to understand what it does -- maybe take 2 seconds instead of 1/2 a second -- it is no biggy in the scheme of things. But understanding the overall flow of the subroutine or block is far more important, and that -- for me at least -- means being able to see as much of that subroutine or block as -- clearly defined steps -- as possible. Which is why I infinitely prefer the one line versions to your 3 or 5 line examples.

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Of course, I didn't say it would be easier for you to parse.

      I can parse the three lines completely in a single glance, not having to pause to even wonder if the details of some complex expression are worth worrying about yet or not. The whole point of the code is already tucked away in my head after that one glance.

      But, no, I don't usually parse the flow while ignoring nearby details, because I find it rather time-consuming to construct the vague but complex (for me) "initializes $mol to something, but I haven't bothered to figure out what" concept. And such vague bits would just leave a mental snag to trip over repeatedly as I discern the purpose while mentally going over the flow. I find the factored-out bits need at least a nice name for me to be able to smoothly gloss over them when considering the flow. More often, I will understand some details of the factored-out bit before dismissing those details from consideration of the current flow (usually by assigning a decent name to that bit -- which is why subroutines are such a good way to factor out bits of complexity; they each get assigned a name).

      The expression is complex enough that I can't tell that it is simply initializing the variable to one of a few different values just by glancing at it. Once I start to parse the expression it takes more effort than a glance. My eyes have to focus on several parts and move back and forth matching up the bits to construct the meaning. By the time I've parsed it enough to tell that it isn't calling some subroutine (that might do complex work), I've already spent more time on the one line then I would have spent on the several lines and yet I still don't understand what the code is doing.

      Both of my multi-line versions parse effortlessly for me. I am not aware of even moving my eyes during the parsing. My mental focus smoothly shifts to each line, in order, instantly understanding the full code of the line and then the next line neatly snaps another detail onto the mental model without the need for any backtracking or restructuring.

      The worst problem of the relative bloat in number of lines is if the logical block of code (almost always a subroutine) gets pushed beyond "one screen full" and thus can't be parsed with just simple and fast eye movements. And that would usually lead to me being less "extravagant" or to factoring out some logical sub-section.

      my $mol = defined $n ? ( $n == 42 ? 'fourty two' : '' ) : 'n/a';

      That is a relative strain to parse in comparison. My experience is that matching up parens is one of the most time-consuming parsing tasks for humans (I've tested it using slide shows and even people who claim to match up parens easily can't do it quickly, IME). The constructs involved are not visually apparent. I'm forced to individually recognize single characters and then mentally re-assemble the logical structure from too many tiny pieces.

      This all reminds me of why newspapers print in rather narrow columns and how many people can read such very quickly without their eyes zigging back and forth (I don't think I'm one of those people, though).

      There are two ways I might try to parse that one complex line. The way that always works is to parse the components of it in order. That is slow because the number of parts to parse is much larger (for me) in the one-line case than in the multi-line cases.

      Using newlines to show each mental pause point, the code ends up in my head like:

      my $mol = defined $n ? ( $n == 42 ? 'fourty two' : '' ) : 'n/a' ;

      And then I have to backtrack several times to line up the '(' and the ')' and to line up the 2nd ':' with the first '?' and then it isn't obvious to me when which of the three values get chosen until I mentally simulate running the code, putting the conditions and values into proper association as I go.

      The second method is to glance over the code, recognizing the "obvious" bits and then filling in the gaps between them. That, for me, starts out as:

      my $mol = <noise> 'fourty two' <noise> 'n/a';

      Then I have to visually and mentally jump between the two "noise" piles and (frustratingly) spend mental effort dealing with single characters. Worse, I then have to tie single characters that aren't next to each other together in a complex structure that isn't represented visually.

      My last example gets parsed so smoothly for me. It is just 4 simple visual pieces that are also 4 simple mental pieces:

      my $mol = ! defined $n ? 'n/a' : 42 == $n ? 'forty two' : '';

      The second piece is the best example of why I prefer my version to yours:

      my $mol = defined $n ? ( $n == 42 ? 'fourty two' : '' ) : 'n/a'; # ^^^^^^^^^^ ^^^^^

      'n/a' is the value that represents "not defined". This is so very much more obscured in your version of the code. It is a single visual and mental chunk in my versions. No re-assembly required.

      Your mileage may vary, obviously.

      Note that I'm talking tiny optimizations here. It might take me 1 or even 2 seconds to parse your complex line. But when reading code, spending that much time on a line is a very long time. When the lines aren't complex, I can scan a whole screen of code in 1 second and understand it.

      And it isn't that I find your most complex line of code unacceptable or even fundamentally difficult to parse. I'd even write the following:

      my $mol = ! defined $n ? 'n/a/' : $n == 42 ? 'fourty two' : '';

      if I had a well-factored subroutine that barely fit on a screenful of lines with that as one of them.

      But if I got the subroutine factored to be smaller, I'd get extravagant with those short expressions and be so happy to re-parse and understand the whole subroutine without even having to degrade out of just needing quick glances.

      - tye        

        Geez! And people call me contrary! But each to their own :)

        Which neatly segways to my theme of the month: Imposing opinions in the name of best practices or automated critique, is fundamentally flawed.

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re^2: Two simple code style advice questions (tye)
by choroba (Bishop) on Jan 18, 2013 at 09:42 UTC
    Your "funny" example does not work:
    # perl -MData::Dumper -e 'my @tests = 1 .. 10; @{ \my %ntests }{ @test +s } = (0) x @tests; print Dumper \%ntests;' $VAR1 = {};
    The problem is the my.
    لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Well, I'd say the problem is that @{ } is defined syntactically as containing a full-fledged block (and thus it imposes its own lexical scope).

      @$_{@tests} = (0)x@tests for \my %ntests;

      - tye        

Re^2: Two simple code style advice questions (tye)
by Tux (Abbot) on Jan 18, 2013 at 16:17 UTC

    But I've come to find ternaries to often be less quick/easy to read than something like:

    I am with BrowserUK here, and I am happy to see you are using the "I find" instead of the way to often used "it is better to" (here in the monastery), as many idioms that are easy to parse by person A causes headaches to person B.

    Personally I would try to avoid statement modifiers to any cost. I hate them. They make me read code exactly opposite of what the author meant.

    I have no trouble reading (nested) ternary operations. Maybe too used to those from doing C.

    You also doing java? Where 42 == $n is quite often preferred over $n == 42 because of "string".equals ($n) implies NULL checks.

    Enjoy, Have FUN! H.Merijn
      You also doing java?

      Nope. I started trying out "42 == n" in C a long time ago to avoid accidentally writing "if( n = 42 )".

      In this case, I wrote "42 == $n" as I find "42" to be the much more interesting part of the expression. I prefer to put shorter things and more interesting things first to speed parsing.

      - tye        

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1013951]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (7)
As of 2018-06-20 08:04 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (116 votes). Check out past polls.