Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re: Think for yourself.

by tilly (Archbishop)
on Oct 05, 2003 at 22:34 UTC ( [id://296806]=note: print w/replies, xml ) Need Help??


in reply to Think for yourself.
in thread is the use of map in a void context deprecated ?

Thinking for myself, I still think that it is poor style.

What is the difference between what these lines should do?

map do_something($_), @some_list; do_something($_) for @some_list;
They should do the same thing. But to my eyes the second reads much more clearly, and I believe that the same holds true at virtually any level of Perl expertise.

If there is a clear way and an unclear way of writing the same thing, with both taking similar effort and length, I call it bad style to deliberately use the unclear one (unless confusion is your goal).

In fact the only reasons that I have seen given for why to use map (and yes, I have seen people try to recommend it) is that it is compact and demonstrates that you really know Perl. I cannot think of a worse reason to (mis)use a feature. Particularly since the goal is not achieved. Inline loops are even more compact, and are more likely to make a positive impression on good Perl programmers.

This does not, of course, justify deriding someone who has picked up the meme of map in void context. But it does indicate gently pointing out that there are clearer ways to do the same thing.

Replies are listed 'Best First'.
Re: Think for yourself.
by Abigail-II (Bishop) on Oct 06, 2003 at 08:51 UTC
    What is the difference between what these lines should do?
    map do_something($_), @some_list; do_something($_) for @some_list;
    They should do the same thing. But to my eyes the second reads much more clearly, and I believe that the same holds true at virtually any level of Perl expertise.

    Well, they don't do the same thing; or rather, you cannot deduce from this code fragment whether they will do the same thing or not. If you want to be sure they are the same, you have to write the latter line as:

    () = do_something ($_) for @some_list;
    Context matters. map gives list context to the expression, while the expression with the for-modifier is in void context.

    And of course, there's another common way of writing map expressions:

    map {BLOCK} @some_list;
    Writing that in for-modifier style gives you:
    () = do {BLOCK} for @some_list;
    Although if the context doesn't matter, you can get away with:
    do {BLOCK} for @some_list;
    Alternatively, you can write it as for statements:
    for (@some_list) { () = do {BLOCK}; }
    or
    for (@some_list) { BLOCK; }
    depending on whether context matters or not.

    If there is a clear way and an unclear way of writing the same thing, with both taking similar effort and length, I call it bad style to deliberately use the unclear one (unless confusion is your goal).
    What is unclear and what is clear is very subjective. For a language that comes with opinions on what is good and what is bad style, see http://www.python.org. However, I find it difficult to believe there are people that find map in void context "unclear", "obfuscated" or "bad style". I can certainly understand people having problems with map. But I find it hard to believe there are seasoned Perl programmers that have no problem with map if the map is on the right hand side of an assignment, but are suddenly getting confused if they assignment disappears.

    What is your feeling if you see:

    user_defined_function {BLOCK} LIST;
    Utter confusion? Or is this ok, as long as it's not called 'map'?
    This does not, of course, justify deriding someone who has picked up the meme of map in void context. But it does indicate gently pointing out that there are clearer ways to do the same thing.
    I disagree. It's ok to say that you have problems understanding the concept of map in void context, and that you prefer another style. But it's not ok to suggest that getting confused over a map in void context is something that all Perl programmers suffer from. Just point out it's your own personal preference.

    Abigail

      But I find it hard to believe there are seasoned Perl programmers that have no problem with map if the map is on the right hand side of an assignment, but are suddenly getting confused if they assignment disappears.

      Im with the bad style chanters on this one, although a borderline case, I dont froth at the mouth over it, and think the optimisation patch is a worthwhile addition to perl.

      I emphasised one point of your comment however. When i see a map in void context that isnt part of an obfu or some CB whip-it-together, my first thought is "Hmm, what happend to the target of the map?" And then I go looking to see what I dont understand. And then I get annoyed and change it to a for loop so that nobody else wastes time trying to figure out the misleading code.

      Theres a great experiment for demonstrating this type of principle.

      PURPLE GREEN BLACK RED BLUE YELLOW

      Now read off the color of each word in the list quickly. Make any mistakes? I bet you did.

      And this is the core problem with map in void context. It makes people think that something is happening that isn't, and then when they realize it isn't, they wonder why its not. Its about wasted time. Don't code like that if you work with me, because if I waste any time wondering why that map is there and there isnt a damn good excuse for it then you and I are going to be having an unpleasant conversation. Now if you decide to rework what was formerly a map without changing it to a for, and leave me a note in a comment I wont be so bothered. I probably wont even change the code for you, accepting it under the Shit Happens rule.

      # this should be changed to a for, dont worry about it

      But if I waste time trying to figure out if the missing part of the map is the cause of some trouble then i'm really not going to be happy.

      For me the core of this is that Larry made the language wonderfully expressive so we con convey the maximum information about what we are doing by the constructs we use to do it. Just as languages have nuances and subtleties so too does perl. And when you mean one thing, and then say it in a way that is usually reserved for saying other things then you are potentially and unnecessarily confusing your audience. The cues they are trained to look for are lying to them. Frankly programming is a complex enough job without wondering if the code is lying to me. (It might be fun in obfus and japhs, but it ends there.)

      ---
      demerphq

        First they ignore you, then they laugh at you, then they fight you, then you win.
        -- Gandhi


        I emphasised one point of your comment however. When i see a map in void context that isnt part of an obfu or some CB whip-it-together, my first thought is "Hmm, what happend to the target of the map?" And then I go looking to see what I dont understand. And then I get annoyed and change it to a for loop so that nobody else wastes time trying to figure out the misleading code.

        And that is something I don't understand. What makes map so special? Any function in Perl will return something, be it a buildin or a user defined sub, and even operators return values. Why is it that people get all confused if they see a map in void context, and start looking where the return value goes, but they don't have problems with other functions?

        What makes map so special?

        Abigail (really, I'd like to know)

      Let me address various points somewhat out of order.
      However, I find it difficult to believe there are people that find map in void context "unclear", "obfuscated" or "bad style". I can certainly understand people having problems with map. But I find it hard to believe there are seasoned Perl programmers that have no problem with map if the map is on the right hand side of an assignment, but are suddenly getting confused if they assignment disappears.
      This argument rests on a basic fallacy that is easiest to explain by example.

      It is trivial to demonstrate that any competent Perl programmer is unlikely to be seriously confused if a particular line of code is accidentally put at a different amount of indentation than it would normally have been. Certainly any programmer who finds it difficult to cope with this is in the wrong line of business.

      Should we therefore conclude that indentation is not an important aspect of programming style?

      Obviously not. And the reason is that stylistic questions are not fundamentally about whether or not a given programmer can figure out a situation, but rather about subtle points that affect the efficiency with which that programmer works. For instance cuing expectations about the structure of code - as indentation does - makes it easier to skim through and narrow down on the section that is likely to be of interest to work with at the moment. Therefore indentation style is definitely relevant to programming style, even though no programmer has trouble understanding it.

      So it is with map. While I have no trouble understanding a map in void context, using a map for its side-effects violates my expectations of what map is for. Therefore reading code that uses maps for their side-effects is less efficient for me. The flip side is that reading code which tries to avoid interesting side-effects inside of maps can now be more efficient for me than it would be otherwise. Since I read and edit a great deal of my own code, and read and edit rather little that uses map for side-effects, this trade-off is a net win for me.

      What is the difference between what these lines should do?
      map do_something($_), @some_list; do_something($_) for @some_list;
      They should do the same thing. But to my eyes the second reads much more clearly, and I believe that the same holds true at virtually any level of Perl expertise.
      Well, they don't do the same thing; or rather, you cannot deduce from this code fragment whether they will do the same thing or not...
      Note the placement of the word should. Buried in that is a normative expectation. Yes, you can abuse context in any way that you want. But I consider it poor style to use context for anything other than the formatting (or generation) of return results. Yes, I could hold constant an awareness that context could be so (to my eyes mis-)used. But amortized over the code that I deal with, my current expectations pay for themselves.

      What is your feeling if you see:
      user_defined_function {BLOCK} LIST;
      Utter confusion? Or is this ok, as long as it's not called 'map'?
      My opinion is that the author should try hard to set appropriate expectations in the function name and documentation. Furthermore I consider it the duty of the programmer who chooses whether or not to use that function to decide whether or not it is appropriate to use that given his or her environment.

      BTW for future reference, a function of that exact form whose API strongly violates some people's expectations is on_release in ReleaseAction.

      This does not, of course, justify deriding someone who has picked up the meme of map in void context. But it does indicate gently pointing out that there are clearer ways to do the same thing.
      I disagree. It's ok to say that you have problems understanding the concept of map in void context, and that you prefer another style. But it's not ok to suggest that getting confused over a map in void context is something that all Perl programmers suffer from. Just point out it's your own personal preference.
      While I will continue to point out that it is my personal preference and will continue to say why, after this discussion I certainly won't insinuate that map in void context is an undefensible stylistic choice. And the biggest single reason for that is Re: Re: Think for yourself.. That shows how maps in void context can arise as a natural leftover of a productive coding style.
        While I have no trouble understanding a map in void context, using a map for its side-effects violates my expectations of what map is for.

        I think this is the main point where you and I differ. What makes "map" so holy that it shouldn't be used for side-effects? Who or what started this notion? Not Larry, otherwise he wouldn't have made $_ an alias for the list element being processed. Many functions in Perl have side-effects, both user defined and core functions. Why is it fine to have side-effects in a 'for', but not in a 'map'? It's not that 'map' is called 'apply_a_function_and_return_a_list_of_calculated_values'. 'map' just means 'map a function over a list' - and I've been familiar with both the name and its function longer than Perl exists.

        Abigail

Re: Re: Think for yourself.
by gwadej (Chaplain) on Oct 06, 2003 at 03:24 UTC

    The main reason I tend to use map is to signal to the reader of the code that this is an operation on a list not just on a set of values that are conveniently represented as an array.

    In other words, to me, map and grep carry extra semantic value to future maintainers of the code. (In most cases, Wade-future does not really remember what Wade-past had in mind.<grin/>)

    To me, your first example implies that we are transforming a list. The second implies we are transforming the elements of a list. Although the results are the same to the computer, to the programmer the meaning may be very different.

    G. Wade
      Then we extract different semantic value from the same code. To me both grep and map make me start looking for where the return is going, because the return is likely to be the point of the operation. By contrast a for loop tells me that the action of the loop is what I should focus on. This bias is strong enough that while I am happy to have loops have side-effects, I will go out of my way to rewrite maps or greps with side-effect in their blocks to be regular loops instead.

      If you are not the only maintainer of your code, it might be worthwhile to find out what both constructs mean to them. Remember that meaning is highly dependent on the context that the reader brings to the document. If people around you read it the same way, then the map solution may well be more maintainable in your environment. If they read it differently, then it may be better to retrain your intuition to match theirs. This kind of issue is one where having people be on the same page matters more than what page everyone is on.

        I agree... the use of map in a void context also makes me look for how the return value is used, because to me, getting a return list is the main reason for using map. This type of distinction reminds me of the section in perlstyle that says:

        Just because you CAN do something a particular way doesn't mean that you SHOULD do it that way. Perl is designed to give you several ways to do anything, so consider picking the most readable one. For instance

        open(FOO,$foo) || die "Can't open $foo: $!";

        is better than

        die "Can't open $foo: $!" unless open(FOO,$foo);

        because the second way hides the main point of the statement in a modifier. On the other hand

        print "Starting analysis\n" if $verbose;

        is better than

        $verbose && print "Starting analysis\n";

        because the main point isn't whether the user typed -v or not.

        To me, using map in a void context seems like "hiding" the main point of the code. And I'll point that out to people, but there are much more flameworthy transgressions. :-)

        -- Mike

        --
        XML::Simpler does not require XML::Parser or a SAX parser. It does require File::Slurp.
        -- grantm, perldoc XML::Simpler

        I'm sorry. I appear to have added to the confusion, rather than clarifying. I should have begun by saying that I avoid using map or grep in void context.

        What I was commenting on was your suggestion that the only reason for using those operators was that they are more concise and show a better grasp of Perl.

        An example of what I was trying to say is the code example below.

        my @minutes = map { $_ / 60 } @seconds;

        In the foreach style, this would be

        my @minutes = (); foreach my $sec (@seconds) { push @minutes, ($sec / 60); }

        To me, the first signals the intent to transform a list of times in seconds into an equivalent list in minutes. The second has pretty much the same effect, but I have to read the code to see what the output is. In the first case, it seems obvious (to me, at least) that the output is the left side of the assignment.

        Although this may seem like a simple example. I find many times that I can use these operators to reduce the noise characters in code like this. Sometimes that reduction is enough to make the overall code clearer by not spending space on relative minor pieces of logic.

        Granted, if the code inside the block gets complicated enough, I may change to the foreach style to emphasize the fact that this is not a simple transformation.

        I see this as a Perl idiom that can convey information to the maintainer when used carefully. I do agree that it can be horribly misused. (The less I say about that the better.<grin type="embarassed"/>

        G. Wade

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://296806]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (5)
As of 2024-03-28 15:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found