http://qs1969.pair.com?node_id=296742

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

hi,

I've got -3 of reputation for my contribution here.   As the update mentions my use of map in void context, i started searching about map function : i first used SuperSearch and found this.   I read "use of map in void context is deprecated" ..

Then I go on searching through usenet, and in a french newsgroup archives ( fr.comp.lang.perl ) i could read this piece of code showing the use of map in void context is still valid :

on the one hand :
$ perl -wle 'map { print } qw(d c a b)'
d
c
a
b
$ perl -wle 'sort { print "$a<=>$b"; $a cmp $b } qw(e d c a b)'
Useless use of sort in void context at -e line 1.

In perldoc -f map there's no use in a void context and they don't mention it at all.   I hope you can tell me more about it

Thanks in advance,
Arnaud

janitored by ybiC: Convert <a href="http://www.perlmonks.org/index.pl...">dis and dat</a> links to [id://foo|and dem] PM style to not log out monks with cookie set to other domains.

Replies are listed 'Best First'.
Think for yourself.
by Abigail-II (Bishop) on Oct 05, 2003 at 21:54 UTC
    As Zaxo said, it was never deprecated. However, for years there was a band of people that never listened to Larry. Larry said that Perl was there to serve the programmer, and the programmer should never be a slave to the language. Yet, this band of people decided programmers should know the details of the implementation, and should hence know how inefficient perl handled map in void context (due to the fact that map, unlike most other functions, didn't inspect in which context it was running). And this band of people would throw dirt at any programmer that used map in void context, scolding them, as if the Perl programmers were guilty of the perl programmers neglect of making map efficiently. (Use of capital and lower case in the previous sentence is very significant).

    There was another round of mud throwing going on on Usenet last month. It prompted me to followup with the following (I've responded to the stone throwing similar for years):

    Poor style? Why? Return values of print and assignment are usually not used either, but noone considers that poor style.

    The fact that map builds and discards a list when it's used in void context is a bug in *perl*. It's not poor style of the Perl programmer; the fault lies with the perl programmers.

    But noone has found it seriously enough to provide a patch. For years, a whole chorus on people in this newsgroup chant "poor style" whenever someone uses map in void context. But none of those sheep has ever bothered sending a patch to p5p.

    And that triggered Tassilo v. Parseval to write a patch. It turned out to be a three line patch. Imagine, all the energy wasted scolding at innocent programmers, while the fix was relatively easy!

    Don't get intimidated to easily when people are chanting "bad style". Chargo cult chanting is in the Perl world far more common than cargo cult programming (although many people will easily chant "cargo cult programming"!). Think for yourself. And people that chant "bad style", think for yourself too. Don't mindlessly copy the behaviour of someone who is "famous". That's how religions start. Think for yourself.

    Abigail

      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.

        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

        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

      You might find this quote interesting, as might others.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail

      And I will continue chanting bad style for the reasons tilly mentioned (and not because it's tilly; I've thought the same for myself a long time). The only thing map can do that for can't, is that you can chain the former but not nest for modifiers. (Which is going to be allowed come Perl 6, thank Larry.)

      Not everyone who chants is cargo cult chanting.

      Makeshifts last the longest.

      Abigail-II: That "three line patch" is one of thousands that bloats Perl. If you want to discourage people from calling this a bad thing, we can't stop you.

      With regards to your argument that nobody considers it bad style that the return value of print and other functions are not checked, I disagree. Many people consider it bad style, but see no practical solution to the problem. People have argued for years (on and off) that print should really raise an exception. The matter has never been closed off. It has only been put off.

      With regards to your argument that it is really a bug that map in void context creates a list, I find your argument to be faulty. It is only the knowledge that the 3 lines patch has been applied (i.e. intimate implementation knowledge of the language) that has since encouraged people to continue to use map in void context. Intuitively, and according to the original documentation, most reasonable people would assume that a list was created, and would only be pleasantly surprised to find that the case was optimized now so that the list is not created.

      With regards to your last argument that calls all people who disagree with you "sheep", and points out that no patch was provided, I think you have missed the point. The people who consider it bad style did not *want* to submit a patch. They did not *want* Perl to be officially implemented to encourage such a bad style. And yet, now that a patch was submitted, and included, this very thing has happened. Respected members of the Perl community such as yourself encourage (or silence the discouragers, which is the same thing) the very odd practice of using a list transformation control structure to iterate through a list.

      It isn't as if this sort of practice is un-Perl. After all, Perl is the language that encourages people to use operations like "tr/a/a/" to count the number of a's in a string.

      I use Perl because it is practical. I don't use it to ensure that non-Perl-familiar members of the community will be unable to understand my code.

        That "three line patch" is one of thousands that bloats Perl.

        If an optimization that only takes three lines "bloats" Perl, then you must have been an unhappy camper ever since Perl 5.000 came out. If you already consider this bloat, how do you feel about statement modifiers? What about having unless? What about short cuts like +=? Or having two kinds of for/foreach, a while, and an until? Shouldn't that be all bloat because we have goto?

        It isn't as if this sort of practice is un-Perl. After all, Perl is the language that encourages people to use operations like "tr/a/a/" to count the number of a's in a string.
        Funny that you bring this one up. For a long time, "tr/a/a/" modified the string it was working on (replacing every 'a' with an 'a'). Noone considered that bad style. And still, after a couple of years, this operation was also optimized. Do you consider that 'bloat' as well?

        I use Perl because it is practical. I don't use it to ensure that non-Perl-familiar members of the community will be unable to understand my code.
        You must have a limited view of the world of programming languages. The non-Perl world is bigger than Java. There are languages in which map like constructs *are* the way to iterate over an array. In fact, I know more languages that use map like constructs to iterate over an array (or list) than I know that use 'for (LIST)'. And outside of Perl, I do not know any that uses 'EXPR for LIST'.

        Abigail

        my @L = map { fix($_->[4]); fix($_->[8]); [ @$_[0,2,3,6,4,8] ] } grep { @$_ == 10 and ($_->[7] eq 'IP') and ($_->[9] eq 'local') } map { [ split ] } <F>;

        i think map in void context is just fine. if i decided to place my data in a hash for later lookup i just might do so at the end of the first map (instead of returning an array of arrays). i'm sure i wouldn't try and re-craft the code to use a for just to appease.

        much in the same way i use the 'useless' cat in my shell pipelines.

        $ cat foo.txt | fgrep blah

        it's much easier to decide to add more files to the cat (try that with <file ). or to replace the cat with another command that generates the data. why on earth would i continuously rewrite my commands when i can up-arrow and add easily to the beginning?

        $ fgrep blah <foo.txt | consolidate | dump $ preproc <foo.txt | fgrep blah | consolidate | dump $ additional <foo.txt | preproc | fgrep blah | consolidate | dump # vs $ cat foo.txt | fgrep blah | consolidate | dump $ cat foo.txt | preproc | fgrep blah | consolidate | dump $ cat foo.txt bar.txt | additional | preproc | fgrep blah | consolidat +e | dump $ real_stream | additional | preproc | fgrep blah | consolidate | dump

        i'll keep my useless cat and my map in void context thank you much. they're my artifacts of iterative development.

        (i.e. intimate implementation knowledge of the language)

        Reading the latest perldelta is hardly "intimate implementation knowledge".

        They did not *want* Perl to be officially implemented to encourage such a bad style.

        Perl has never cared about discouraging "bad" style. If you want that, you'd probably enjoy Python or Java. It's a little late for Perl to start doing the same.

        After all, Perl is the language that encourages people to use operations like "tr/a/a/" to count the number of a's in a string.

        Thanks, I didn't know about that one :)

        ----
        I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
        -- Schemer

        Note: All code is untested, unless otherwise stated

Re: is the use of map in a void context deprecated ?
by Zaxo (Archbishop) on Oct 05, 2003 at 18:31 UTC

    Void map has never been deprecated in the official sense that pseudo-hashes, v-strings, and $* are. Maybe a better word would be derided. The map function produces a copy of the post-map list which is useless in void context and immediately thrown away. Optimizers dislike that, particularly when a for loop can do better.

    I seem to recall that map was just rewritten to check for void context and avoid the extra work if possible. That would remove all objections but aesthetic ones, shouts of "Ugly!" which need not be listened to. I'll try to remember where I saw that.

    After Compline,
    Zaxo

      ...I seem to recall that map was just rewritten to check for void context and avoid the extra work if possible.

      That is correct. And it's in Perl 5.8.1! From the 5.8.1. perldelta:

      "map" in void context is no longer expensive. "map" is now context aware, and will not construct a list if called in void context.

      Liz

        I didn't know perldelta('s), we can learn a lot from it ...
        Let me sharing this :
        "Switch", by Damian Conway, has been added. Just by saying :
        use Switch;
        Fore more information on this module :
        $ perldoc Switch

        Thanks Liz and Zaxo for answering,

        Arnaud