Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

Insensitive Scoundrel

by bluto (Curate)
on Sep 26, 2002 at 16:18 UTC ( #200949=perlmeditation: print w/replies, xml ) Need Help??

Until now I've always tried to use grep, map, qx and other functions that return values "properly", by not using them in a void context (i.e. by not letting them waste time and memory by accumulating a result that will just be thrown away). I've started to question this behavior though. After all, the FAQ says...

What's wrong with using grep or map in a void context? Both grep and map build a return list, regardless of their context. This means you're making Perl go to the trouble of building up a return list that you then just ignore. That's no way to treat a programming language, you insensitive scoundrel!

Now I guess my question is: "Why is perl bothering to accumulate results when it knows it's being called in a void context?" For example, I've written backticks/system replacements that add additional features I like (e.g. like logging). I've had them check the context (with wantarray), and not even accumulate output if called within a void context. Why can't Perl do the same thing, and leave me with a clear conscience about being lazier than I am now?


Replies are listed 'Best First'.
Re: Insensitive Scoundrel
by thraxil (Prior) on Sep 26, 2002 at 17:01 UTC

    the FAQ states a good technical reason for avoiding map/grep in a void context. however, i think the most important reason is just that almost any time you'd want to use map or grep in a void context, what you really want is just a foreach loop or something.

    map and grep have long histories as list filters that take a list in and spit a list out. using them in a void context reduces them to mere looping constructs. if you need a looping construct, foreach is almost always more appropriate. using map or grep just makes the code more confusing for no good reason.

    anders pearson

Re: Insensitive Scoundrel
by tadman (Prior) on Sep 26, 2002 at 18:10 UTC
    It's probably a case of keeping things simple. After all, why make map operate like for when you already have a perfectly servicable for-loop mechanism.

    Like using a screwdriver to stir paint, or hammer in a nail, you can use map and grep to iterate. Unlike other programming languages, there's nothing to stop you. They work, just not as well.

    You can also use C's malloc() in void context too. Just don't whine when you wonder where all your memory has gone.
      I use a screwdriver to open a paint can. They make special tools just for opening paint cans, but I find that excessive--why buy and not lose another small tool, and keep it around and gather it up as part of a painting project? The screwdrivers are among the most common and versatile tools in my typical work, and I have then ready at hand.

      So, why do we even have foreach and map as separate constructs when they do the same thing? Perhaps only for historical reasons. It makes sense to have a looping construct that applies a block to each item in a list. Now if the construct itself were to return a value, what would that value be? A list of all the "results" of the block makes perfect sence. So if you could use foreach as an expression rather than a statement, it would naturally be map.

      And we all know that grep is a trivial usage of map. We don't really need it as a core part of the language, any more than we need chop.


        It's almost as if pop and shift should work on scalars, don't you think? Then you can ditch chop as being silly.

        You have a bit of a point, but for is a lot more than just map. It does different things. For example:
        for my $foo (@bars) { next if ($foo > 10); last if ($foo == 42); $foo += 12; }
        Now, what would you expect that loop to return, if it were like a map? You can't skip or restart map in the same way, you realise, probably because it could cause some very strange behavior.

        I'm all for condensation where it makes sense, but in this case, I think you're going to have a Swiss-Army-like function and no heavy lifting tools.

        Careful, you're about to reinvent the lambda calculus!

        This seems entirely reasonable to me.

        I guess the generalization of this would be for the Perl Run-time system (the Bytecode interpreter or Parrot or whatever) to recognize when a routine is being called in a void context and to propagate down to all callees to not bother assigning to or otherwise generating any data structure that is to be returned, unless that data structure is needed for other processing.

        It also might simplify Perl to then define foreach in terms of map, etc.

Re: Insensitive Scoundrel
by hding (Chaplain) on Sep 27, 2002 at 13:37 UTC

    I think it's a perfectly sane thing to want. In Common Lisp, for example, there are functions analogous to Perl's map that accumulate a return list (e.g. mapcar, and others that don't (e.g. mapc), plus the all-encompassing Lisp map that allows one to specify what kind of sequence one wants returned (e.g. list, vector, string) or none at all. It's nice to have all that available when you don't want to write an explicit loop.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://200949]
Approved by TStanley
Front-paged by ChemBoy
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (7)
As of 2017-03-30 18:49 GMT
Find Nodes?
    Voting Booth?
    Should Pluto Get Its Planethood Back?

    Results (362 votes). Check out past polls.