Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Style question: map versus foreach

0 views
Skip to first unread message

LaDainian Tomlinson

unread,
Nov 7, 2003, 2:05:35 PM11/7/03
to
Hi,

I wrote a short script the other night to search for C errno definitions by
their integer values. It works fine, but I was originally using map() in
void context and figured that was bad practice. Is this true at all, or are
there any advantages to using map() (speed-wise or otherwise) rather than a
foreach loop even in void context? The script follows:

--- BEGIN CODE ---
#!/usr/bin/perl

use warnings;
use strict;
use File::Find;

my @errnos;
my $errnum = 21;

find(\&wanted, qw(/usr/include));

$\ = "\n";
foreach (@errnos){
open ERRNO, "<", $_ or die "Couldn't open $_: $!";
#map { chomp && print if /\b$errnum\b/ } <ERRNO>; #this?
foreach (<ERRNO>){ chomp && print if /\b$errnum\b/ }; #or this?
close ERRNO or die "Couldn't close $_: $!";
}

sub wanted { push(@errnos, $File::Find::name) if /errno.h$/ }
--- END CODE ---

Thanks,

Brandan L.
--
bclennox AT eos DOT ncsu DOT edu

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.532 / Virus Database: 326 - Release Date: 10/27/2003


Tassilo v. Parseval

unread,
Nov 7, 2003, 2:20:17 PM11/7/03
to
Also sprach LaDainian Tomlinson:

> I wrote a short script the other night to search for C errno definitions by
> their integer values. It works fine, but I was originally using map() in
> void context and figured that was bad practice. Is this true at all, or are
> there any advantages to using map() (speed-wise or otherwise) rather than a
> foreach loop even in void context? The script follows:

[...]

Depends on the version of perl you employ. When you are using 5.8.1
map() no longer bothers to return a list in void context which makes it
almost (but not quite, as I remember) fast as a foreach-loop.

For older perls, there is a measurable difference in speed favouring
foreach. If in doubt, use the Benchmark module to get some figures for
your machine.

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval

Roy Johnson

unread,
Nov 7, 2003, 5:07:37 PM11/7/03
to
"LaDainian Tomlinson" <g...@away.spam> wrote in message news:<32Sqb.90992$IA2.3...@twister.southeast.rr.com>...

> #map { chomp && print if /\b$errnum\b/ } <ERRNO>; #this?
> foreach (<ERRNO>){ chomp && print if /\b$errnum\b/ }; #or this?

Or maybe
print grep (chomp && /\b$errnum\b/) <ERRNO>;
?

Anno Siegel

unread,
Nov 7, 2003, 8:21:22 PM11/7/03
to
Tassilo v. Parseval <tassilo....@post.rwth-aachen.de> wrote in comp.lang.perl.misc:

> Also sprach LaDainian Tomlinson:
>
> > I wrote a short script the other night to search for C errno definitions by
> > their integer values. It works fine, but I was originally using map() in
> > void context and figured that was bad practice. Is this true at all, or are
> > there any advantages to using map() (speed-wise or otherwise) rather than a
> > foreach loop even in void context? The script follows:
>
> [...]
>
> Depends on the version of perl you employ. When you are using 5.8.1
> map() no longer bothers to return a list in void context which makes it
> almost (but not quite, as I remember) fast as a foreach-loop.
>
> For older perls, there is a measurable difference in speed favouring
> foreach. If in doubt, use the Benchmark module to get some figures for
> your machine.

That's efficiency. As for style, that depends very much upon whom
you ask. Some want to ban map in void context entirely, others say
there's nothing wrong with it. I tend to avoid it since (namely 5.1.1
or so) the statement-modifying "for" does the same thing.

Anno

Tassilo v. Parseval

unread,
Nov 8, 2003, 1:53:57 AM11/8/03
to
Also sprach Anno Siegel:

I think map() allows for some suggestive notations if one rememebers
that it applies a chunk of code to each element of a list. Someone with
an affinity to functional programming might like idioms such as

local $\ = " " and map print() => qw(Just another Perl hacker,);

On the other hand, this is likely to confuse a rather
imperatively-minded programmer.

Abigail

unread,
Nov 9, 2003, 9:01:19 AM11/9/03
to
LaDainian Tomlinson (g...@away.spam) wrote on MMMDCCXX September MCMXCIII
in <URL:news:32Sqb.90992$IA2.3...@twister.southeast.rr.com>:

<> Hi,
<>
<> I wrote a short script the other night to search for C errno definitions by
<> their integer values. It works fine, but I was originally using map() in
<> void context and figured that was bad practice. Is this true at all, or are
<> there any advantages to using map() (speed-wise or otherwise) rather than a
<> foreach loop even in void context? The script follows:


I'm curious, what made you think that map () in void context was bad
practice?

Abigail
--
$"=$,;*{;qq{@{[(A..Z)[qq[0020191411140003]=~m[..]g]]}}}=*_=sub{print/::(.*)/};
$\=$/;q<Just another Perl Hacker>->();

LaDainian Tomlinson

unread,
Nov 9, 2003, 1:11:53 PM11/9/03
to
"Abigail" wrote:
> LaDainian Tomlinson (g...@away.spam) wrote on MMMDCCXX September MCMXCIII
> in <URL:news:32Sqb.90992$IA2.3...@twister.southeast.rr.com>:
> <> Hi,
> <>
> <> I wrote a short script the other night to search for C errno
definitions by
> <> their integer values. It works fine, but I was originally using map()
in
> <> void context and figured that was bad practice. Is this true at all,
or are
> <> there any advantages to using map() (speed-wise or otherwise) rather
than a
> <> foreach loop even in void context? The script follows:
>
>
> I'm curious, what made you think that map () in void context was bad
> practice?

I guess I don't like discarding return values. It seems like a bad habit to
get into. At least in this case, it could have easily been avoided with a
solution like Roy's (printing the list returned by grep() or map() rather
than printing in the map() itself).

Thank you all for the help,

Ben Morrow

unread,
Nov 9, 2003, 2:36:46 PM11/9/03
to

"LaDainian Tomlinson" <g...@away.spam> wrote:

> "Abigail" wrote:
> > I'm curious, what made you think that map () in void context was bad
> > practice?
>
> I guess I don't like discarding return values. It seems like a bad habit to
> get into.

From 'info gcc':

| Coming as I do from a Lisp background, I balk at the idea that there
| is something dangerous about discarding a value. There are
| functions that return values which some callers may find useful; it
| makes no sense to clutter the program with a cast to `void' whenever
| the value isn't useful.

*Everything* returns a value[1]: a statement such as

my $i = 5;

returns $i, which you then discard.

Ben

[1] OK, with a couple of exceptions, such as 'package'...

--
Musica Dei donum optimi, trahit homines, trahit deos. |
Musica truces molit animos, tristesque mentes erigit. | b...@morrow.me.uk
Musica vel ipsas arbores et horridas movet feras. |

Darin McBride

unread,
Nov 9, 2003, 6:14:17 PM11/9/03
to
Ben Morrow wrote:

>
> "LaDainian Tomlinson" <g...@away.spam> wrote:
>> "Abigail" wrote:
>> > I'm curious, what made you think that map () in void context was bad
>> > practice?
>>
>> I guess I don't like discarding return values. It seems like a bad habit
>> to get into.
>
> From 'info gcc':
>
> | Coming as I do from a Lisp background, I balk at the idea that there
> | is something dangerous about discarding a value. There are
> | functions that return values which some callers may find useful; it
> | makes no sense to clutter the program with a cast to `void' whenever
> | the value isn't useful.

I suppose it all depends on what you're trying to do. And it depends
on what choices you have. For example, as long as we're on gcc (which
usually also does C++), using ++i vs i++ can have huge impacts on
speed. Both return a value, but that value is usually discarded. So
which one to use?

In Perl, we have the same choice with "use overload" to some degree
(perl is smart enough to do the Right Thing if your increment function
is done right).

If the 'i' object is a heavy type where copying it can be expensive,
then you definitely want to use "++i" because that can then return a
reference to i after the increment is finished. However, "i++" will
copy itself, increment itself, and then return the copy (by value, not
reference).

Thus, even when discarding a return value, it can be important to use
the right version. If you're discarding the return from ++, then use
the preincrement - it can be tons faster. And where it isn't, it can't
be any slower than postincrement.

Similarly with map vs for/foreach. If you're discarding the return
value from map, then why bother at all? It's much clearer to use
foreach instead. And, as reported, foreach is still marginally faster
than map in cases where you ignore the return from map. Clarity AND
speed - what more can one ask for?

Now, if you're writing another JAPH sig or competing for obsfucated
code, map may make more sense. But for any code that might need
maintenance, write the code that means what you want it to do. In this
case, foreach.

I think I use map more than foreach, but that's because I'm constantly
rewriting my arrays, or converting arrays to hashes, or converting
hashes to arrays or other nonsense. I use the return values. I figure
that this is probably faster than writing it in foreach, and besides,
that's what I mean to do - completely clear.

> *Everything* returns a value[1]: a statement such as
>
> my $i = 5;
>
> returns $i, which you then discard.

The difference is that this "returns" a single scalar. Map allocates
and returns an array (or at least, that's the concept). Big
difference.

Abigail

unread,
Nov 9, 2003, 7:10:48 PM11/9/03
to
LaDainian Tomlinson (g...@away.spam) wrote on MMMDCCXXII September MCMXCIII
in <URL:news:Jrvrb.91943$fl1.3...@twister.southeast.rr.com>:
## "Abigail" wrote:
## >
## > I'm curious, what made you think that map () in void context was bad
## > practice?
##
## I guess I don't like discarding return values. It seems like a bad habit to
## get into. At least in this case, it could have easily been avoided with a
## solution like Roy's (printing the list returned by grep() or map() rather
## than printing in the map() itself).

print returns a value, which is discarded in void context..
Assignment returns a value, which is discarded in void context.
s/// returns a value, which is discarded in void context.
pop returns a value, which is discarded in void context.
map returns a value, which is discarded in void context.


Do you think that using any of these five operations in void context is
bad practise? If not, could you indicate why using some operations in
void context is fine, but map in void context is bad practise? Because
I really fail to see what map has done to get this special status.

Abigail
--
INIT {print "Perl " }
CHECK {print "another "}
BEGIN {print "Just " }
END {print "Hacker\n"}

Abigail

unread,
Nov 9, 2003, 7:19:57 PM11/9/03
to
Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXII
September MCMXCIII in <URL:news:dTzrb.355948$6C4.127445@pd7tw1no>:

""
"" The difference is that this "returns" a single scalar. Map allocates
"" and returns an array (or at least, that's the concept). Big
"" difference.


Wrong. First of all, from the language point of view, what a function
returns is determined by the *CONTEXT*, not the function. As Randal
likes to chant "there are no lists in scalar context". So, a function
in void context (it being a special case of scalar context) simply
*cannot* return a list (arrays are never returned by Perl anyway).

Secondly, the fact than in older versions of Perl map was implemented
inefficiently was a bug in perl, that now is luckely fixed. But it's
pretty lame to call a certain style of Perl programming "bad practise",
just because the implementation was inefficient. But that's no longer
an issue anymore.


Abigail
--
perl -wleprint -eqq-@{[ -eqw\\- -eJust -eanother -ePerl -eHacker -e\\-]}-

Darin McBride

unread,
Nov 9, 2003, 9:37:25 PM11/9/03
to
Abigail wrote:

> Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXII
> September MCMXCIII in <URL:news:dTzrb.355948$6C4.127445@pd7tw1no>:
> ""
> "" The difference is that this "returns" a single scalar. Map allocates
> "" and returns an array (or at least, that's the concept). Big
> "" difference.
>
>
> Wrong. First of all, from the language point of view, what a function
> returns is determined by the *CONTEXT*, not the function. As Randal
> likes to chant "there are no lists in scalar context". So, a function
> in void context (it being a special case of scalar context) simply
> *cannot* return a list (arrays are never returned by Perl anyway).

No, you're right. I suppose you overlooked the "that's the concept"
part of that paragraph. Context rules in perl. But that doesn't mean
that context rules in the maintainer's head when trying to decipher
what was written.

> Secondly, the fact than in older versions of Perl map was implemented
> inefficiently was a bug in perl, that now is luckely fixed. But it's

That it being fixed is "lucky" is somewhat debatable. That doesn't
make map in void context any more clear than before - only not as bad
for runtime speed vs before the "fix".

Note that the fix is not necessarily goodness. It may have a speed
penalty on array-context map's if it means that all of my 80 map's need
to check their context (which is never void) just so that one of your
map's (in void context) can be zillions faster. That's an overall
negative to perl's speed since I can't speed up my map's any more, but
you could have simply converted to foreach to get an even better (even
if only slightly better) speed increase.

> pretty lame to call a certain style of Perl programming "bad practise",
> just because the implementation was inefficient. But that's no longer
> an issue anymore.

I suppose you also missed pretty much any of my post that you didn't
quote. My point, as opposed to others, is that even without the speed
penalty, there is a stylistic benefit to using foreach when you may
otherwise wish to use map in void context.

It's simply more *obvious* to use map for array contexts and foreach in
void contexts. And that, regardless of any speed difference, is enough
reason to discourage map in void context.

Tassilo v. Parseval

unread,
Nov 10, 2003, 2:20:26 AM11/10/03
to
Also sprach Abigail:

It's a historical thing. It used to always generate a return-list and so
it was bad. It's questionable of course whether this a stylistic
question at all or maybe whether it wasn't simply a shortcoming (or even
a bug) in the implementation. For me it's the latter.

Perhaps some day the same optimization happens for grep (I looked at it
but it's a little more complicated than the map-case). Then these three

$_++ for @a;
map $_++, @a;
grep $_++, @a;

will all behave very similarily in speed although the third version
looks indeed kind of strange since it looks like a conceptual abuse of
grep.

Abigail

unread,
Nov 10, 2003, 4:32:54 AM11/10/03
to
Tassilo v. Parseval (tassilo....@rwth-aachen.de) wrote on
MMMDCCXXIII September MCMXCIII in <URL:news:bone7q$82f$1...@nets3.rz.RWTH-Aachen.DE>:

<>
<> Perhaps some day the same optimization happens for grep (I looked at it
<> but it's a little more complicated than the map-case). Then these three
<>
<> $_++ for @a;
<> map $_++, @a;
<> grep $_++, @a;
<>
<> will all behave very similarily in speed although the third version
<> looks indeed kind of strange since it looks like a conceptual abuse of
<> grep.


Actually, they will all be slightly different:

sub f {
print wantarray ? "LIST" : defined wantarray ? "SCALAR" : "VOID"
}

f () for 1; # VOID.
map f () => 1; # LIST.
grep f () => 1; # SCALAR.


Abigail
--
perl -e '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %;
BEGIN {% % = ($ _ = " " => print "Just Another Perl Hacker\n")}'

Abigail

unread,
Nov 10, 2003, 4:45:51 AM11/10/03
to
Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII
September MCMXCIII in <URL:news:FRCrb.356754$pl3.261426@pd7tw3no>:
__ Abigail wrote:
__
__ No, you're right. I suppose you overlooked the "that's the concept"
__ part of that paragraph. Context rules in perl. But that doesn't mean
__ that context rules in the maintainer's head when trying to decipher
__ what was written.

If you're going to assume the maintainer doesn't know basic concepts
of Perl, all bets are off. Then one might want to avoid hashes and
regexes too.

__ > Secondly, the fact than in older versions of Perl map was implemented
__ > inefficiently was a bug in perl, that now is luckely fixed. But it's
__
__ That it being fixed is "lucky" is somewhat debatable. That doesn't
__ make map in void context any more clear than before - only not as bad
__ for runtime speed vs before the "fix".
__
__ Note that the fix is not necessarily goodness. It may have a speed
__ penalty on array-context map's if it means that all of my 80 map's need
__ to check their context (which is never void) just so that one of your
__ map's (in void context) can be zillions faster. That's an overall
__ negative to perl's speed since I can't speed up my map's any more, but
__ you could have simply converted to foreach to get an even better (even
__ if only slightly better) speed increase.

Of course, map already had to check context. It wasn't that map left
its intermediar list on the stack if it was called in void or scalar
context.

__
__ > pretty lame to call a certain style of Perl programming "bad practise",
__ > just because the implementation was inefficient. But that's no longer
__ > an issue anymore.
__
__ I suppose you also missed pretty much any of my post that you didn't
__ quote. My point, as opposed to others, is that even without the speed
__ penalty, there is a stylistic benefit to using foreach when you may
__ otherwise wish to use map in void context.
__
__ It's simply more *obvious* to use map for array contexts and foreach in
__ void contexts. And that, regardless of any speed difference, is enough
__ reason to discourage map in void context.


"Obvious" is something subjective. *YOU* might find one way of doing
something more obvious than doing it another way. But that doesn't
mean it's true for everyone. Could you please explain why you find
map in void context so non-obvious? Do you think map in general is
non-obvious, or do you only get confused when the context is void?
What about other functions in void context? Are they non-obvious too?
Or is it only map that's non-obvious?

I've had this discussion before, and people sometimes claim they find
map in void context hard to understand but when I point out to them they
happily use other function in void context without a problem, and ask
them why they special case 'map', they don't know.

Is there anyone who can explain why map in void context is confusing,
but other functions aren't?


Abigail
--
perl -we '$@="\145\143\150\157\040\042\112\165\163\164\040\141\156\157\164".
"\150\145\162\040\120\145\162\154\040\110\141\143\153\145\162".
"\042\040\076\040\057\144\145\166\057\164\164\171";`$@`'

Tassilo v. Parseval

unread,
Nov 10, 2003, 5:29:26 AM11/10/03
to
Also sprach Abigail:

> Tassilo v. Parseval (tassilo....@rwth-aachen.de) wrote on
> MMMDCCXXIII September MCMXCIII in <URL:news:bone7q$82f$1...@nets3.rz.RWTH-Aachen.DE>:
><>
><> Perhaps some day the same optimization happens for grep (I looked at it
><> but it's a little more complicated than the map-case). Then these three
><>
><> $_++ for @a;
><> map $_++, @a;
><> grep $_++, @a;
><>
><> will all behave very similarily in speed although the third version
><> looks indeed kind of strange since it looks like a conceptual abuse of
><> grep.
>
>
> Actually, they will all be slightly different:
>
> sub f {
> print wantarray ? "LIST" : defined wantarray ? "SCALAR" : "VOID"
> }
>
> f () for 1; # VOID.
> map f () => 1; # LIST.
> grep f () => 1; # SCALAR.

You are right. The different contextes map() and grep() impose onto their
first argument is something I always forget about. Fortunately it
shouldn't matter in my example (unless $_ holds an object with some
fancy ++-overloading).

Thanks for the reminder,

Ben Morrow

unread,
Nov 10, 2003, 5:35:17 AM11/10/03
to

abi...@abigail.nl wrote:
> Tassilo v. Parseval (tassilo....@rwth-aachen.de) wrote on
> MMMDCCXXIII September MCMXCIII in
> <URL:news:bone7q$82f$1...@nets3.rz.RWTH-Aachen.DE>:
> <> Perhaps some day the same optimization happens for grep (I looked at it
> <> but it's a little more complicated than the map-case). Then these three
> <>
> <> $_++ for @a;
> <> map $_++, @a;
> <> grep $_++, @a;
> <>
> <> will all behave very similarily in speed although the third version
> <> looks indeed kind of strange since it looks like a conceptual abuse of
> <> grep.
>
> Actually, they will all be slightly different:
>
> sub f {
> print wantarray ? "LIST" : defined wantarray ? "SCALAR" : "VOID"
> }
>
> f () for 1; # VOID.
> map f () => 1; # LIST.
> grep f () => 1; # SCALAR.

I like that :) it appeals to my simple mind...

It also gives a specific use for map in void context: to call a
function in list context but discard the result.

Ben

--
It will be seen... that the Erwhonians are a meek and long-suffering people,
easily led by the nose, and quick to offer up common sense at the shrine of
logic, when a philosopher arises among them who... convinc[es] them that their
...institutions are not based on... morality. [Samuel Butler] b...@morrow.me.uk

Anno Siegel

unread,
Nov 10, 2003, 5:56:24 AM11/10/03
to
Tassilo v. Parseval <tassilo....@post.rwth-aachen.de> wrote in comp.lang.perl.misc:
> Also sprach Abigail:
>
> > LaDainian Tomlinson (g...@away.spam) wrote on MMMDCCXXII September MCMXCIII
> > in <URL:news:Jrvrb.91943$fl1.3...@twister.southeast.rr.com>:
> > ## "Abigail" wrote:

[...]

> > print returns a value, which is discarded in void context..
> > Assignment returns a value, which is discarded in void context.
> > s/// returns a value, which is discarded in void context.
> > pop returns a value, which is discarded in void context.
> > map returns a value, which is discarded in void context.
> >
> >
> > Do you think that using any of these five operations in void context is
> > bad practise? If not, could you indicate why using some operations in
> > void context is fine, but map in void context is bad practise? Because
> > I really fail to see what map has done to get this special status.
>
> It's a historical thing. It used to always generate a return-list and so

> it was bad. ...

(bad to use it in void context, I assume)

Historically, the concept of "map" functions was introduced with LISP,
every other language has it from there. Interestingly, the original
LISP "map" doesn't return anything, it is a procedure that is only called
for its side effects. Calling it anywhere *but* in void context is useless.
(You need "maplist" if you want a return value; the real ancestor of other
"map" functions is LISPs "mapcar".)

So the original inventors of "map" didn't share the intuition that "map"
has to return an image.

Anno

Darin McBride

unread,
Nov 10, 2003, 1:25:53 PM11/10/03
to
Abigail wrote:

> Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII
> September MCMXCIII in <URL:news:FRCrb.356754$pl3.261426@pd7tw3no>:
> __ Abigail wrote:
> __
> __ No, you're right. I suppose you overlooked the "that's the concept"
> __ part of that paragraph. Context rules in perl. But that doesn't mean
> __ that context rules in the maintainer's head when trying to decipher
> __ what was written.
>
> If you're going to assume the maintainer doesn't know basic concepts
> of Perl, all bets are off. Then one might want to avoid hashes and
> regexes too.

True to a point. However, there is no cleaner way to do hashes or
regexes. There is a clearer way to do map in void context: foreach.
And that's the crux, too. If there was no foreach, then it would be
obvious to all comers that map in void context is used for a particular
purpose.

However, the general rule is to use map for return values and foreach
when you don't need the return value. And that's what most people are
likely to think. Try reading perldoc perlstyle a bit... a few tidbits:

o 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.

The main point of map is the return value. The main point of foreach
is the iteration over an array (no return value implied).

o Avoid using grep() (or map()) or `backticks` in a void
context, that is, when you just throw away their
return values. Those functions all have return val-
ues, so use them. Otherwise use a foreach() loop or
the system() function instead.

I think this is the whole debate. Unfortunately, there's no real
explicit justification here.

> __ That it being fixed is "lucky" is somewhat debatable. That doesn't
> __ make map in void context any more clear than before - only not as bad
> __ for runtime speed vs before the "fix".
> __
> __ Note that the fix is not necessarily goodness. It may have a speed
> __ penalty on array-context map's if it means that all of my 80 map's
> need
> __ to check their context (which is never void) just so that one of your
> __ map's (in void context) can be zillions faster. That's an overall
> __ negative to perl's speed since I can't speed up my map's any more, but
> __ you could have simply converted to foreach to get an even better (even
> __ if only slightly better) speed increase.
>
> Of course, map already had to check context. It wasn't that map left
> its intermediar list on the stack if it was called in void or scalar
> context.

It's just an extra check. I'm sure it was something like (simplified
for CODE case only):

sub map {
my $code = shift;
my @r;
foreach (@_) {
my @a = $code->();
if (wantarray) {
push @r, @a;
}
else {
$r[0] += scalar @a;
}
}
wantarray ? @r : $r[0];
}

Now it's more like:

sub map {
my $code = shift;
my @r;
foreach (@_) {
my @a = $code->();
if (defined wantarray) {
if (wantarray) {
push @r, @a;
}
else {
$r[0] += scalar @a;
}
}
}
wantarray ? @r : $r[0];
}

That's just an extra level of checks that isn't needed. Of course,
there are other ways to write this - some simpler, others faster. And,
of course, it's probably all in native (C) code anyway. Probably using
a case statement - which has its own overhead.

> __ I suppose you also missed pretty much any of my post that you didn't
> __ quote. My point, as opposed to others, is that even without the speed
> __ penalty, there is a stylistic benefit to using foreach when you may
> __ otherwise wish to use map in void context.
> __
> __ It's simply more *obvious* to use map for array contexts and foreach
> in
> __ void contexts. And that, regardless of any speed difference, is
> enough
> __ reason to discourage map in void context.
>
> "Obvious" is something subjective. *YOU* might find one way of doing
> something more obvious than doing it another way. But that doesn't
> mean it's true for everyone. Could you please explain why you find
> map in void context so non-obvious? Do you think map in general is
> non-obvious, or do you only get confused when the context is void?
> What about other functions in void context? Are they non-obvious too?
> Or is it only map that's non-obvious?

Given that map and foreach do almost exactly the same thing with only
the desired contexts being different, it makes sense to me that one
would use the version one desires based on that context difference.
Thus, when I see map in void context, the first thought in my mind is
"they didn't get the return from map!". Then, after scrutinising the
map's block (as it's usually a block not an expression), I may figure
out that they intended to have void (e.g., only doing it for the side
effect). And then, if that's not the source of the problem, I can go
on.

However, if they had used foreach to begin with, I might have been able
to skip over the code altogether knowing that "ignoring the return" is
exactly what was intended.

> I've had this discussion before, and people sometimes claim they find
> map in void context hard to understand but when I point out to them they
> happily use other function in void context without a problem, and ask
> them why they special case 'map', they don't know.

I do know. It's that there is another, clearer way to do it. There is
no other function other than 'print' to print to a filehandle. So use
it.

> Is there anyone who can explain why map in void context is confusing,
> but other functions aren't?

Simply have your code say what you mean rather than trick the virtual
machine into doing what you want by side effect. In general, side
effects make code harder to understand.

LaDainian Tomlinson

unread,
Nov 10, 2003, 2:27:46 PM11/10/03
to
"Abigail" wrote:
> LaDainian Tomlinson (g...@away.spam) wrote on MMMDCCXXII September MCMXCIII
> in <URL:news:Jrvrb.91943$fl1.3...@twister.southeast.rr.com>:
> ## "Abigail" wrote:
> ## >
> ## > I'm curious, what made you think that map () in void context was bad
> ## > practice?
> ##
> ## I guess I don't like discarding return values. It seems like a bad
habit to
> ## get into. At least in this case, it could have easily been avoided
with a
> ## solution like Roy's (printing the list returned by grep() or map()
rather
> ## than printing in the map() itself).
>
> print returns a value, which is discarded in void context..
> Assignment returns a value, which is discarded in void context.
> s/// returns a value, which is discarded in void context.
> pop returns a value, which is discarded in void context.
> map returns a value, which is discarded in void context.

You are correct, and I know there are loads of others too, not just in Perl.

> Do you think that using any of these five operations in void context is
> bad practise? If not, could you indicate why using some operations in
> void context is fine, but map in void context is bad practise? Because
> I really fail to see what map has done to get this special status.

No, I don't (except for map() :-), and no, I can't. It's simply a judgment
call in most cases whether or not to capture a return value. _Everyone_
knows that you should always, yes *always*, check the return value of
open(), and close(), and system() and various other such functions with
"important" return values. Failing to do so has a high probability of
affecting the way your code works.

However, most of the time you don't necessarily need to know the number of
substitutions made on a string by s/// or the success of the last print
operation, and sometimes you just need to pop the last value on an array.
In these cases, functions are the simplest way to perform such operations,
so the choice is either to capture the return value and do nothing with it,
or just ignore it altogether. And it makes more sense to ignore it. In my
example, there was an easy way to avoid discarding the return value while
still achieving the same behavior. I _personally_ prefer to avoid returns
in void context when possible and plausible. I can't quantify the
importance of return values or draw a line to separate the good ones from
the bad ones, but I still need to make a (possibly informed) decision
between a few different ways of doing something.

Which is why I asked in the first place, and I've gotten a lot of good
insight. So thank you folks.

Abigail

unread,
Nov 10, 2003, 5:30:01 PM11/10/03
to
Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII
September MCMXCIII in <URL:news:RKQrb.361373$6C4.143831@pd7tw1no>:

:: Abigail wrote:
::
:: > Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII
:: > September MCMXCIII in <URL:news:FRCrb.356754$pl3.261426@pd7tw3no>:
:: > __ Abigail wrote:
:: > __
:: > __ No, you're right. I suppose you overlooked the "that's the concept"
:: > __ part of that paragraph. Context rules in perl. But that doesn't mean
:: > __ that context rules in the maintainer's head when trying to decipher
:: > __ what was written.
:: >
:: > If you're going to assume the maintainer doesn't know basic concepts
:: > of Perl, all bets are off. Then one might want to avoid hashes and
:: > regexes too.
::
:: True to a point. However, there is no cleaner way to do hashes or
:: regexes. There is a clearer way to do map in void context: foreach.

But could you give an objective reason why foreach is "clearer" than
map (after defining what "clearer" is)? Or is it your own preference?
What makes foreach cleaner than while? Or is while cleaner than
foreach? Which one ought to go? Or can we have foreach, for, while,
until, goto, and bare blocks, but not map in void context?

:: And that's the crux, too. If there was no foreach, then it would be


:: obvious to all comers that map in void context is used for a particular
:: purpose.
::
:: However, the general rule is to use map for return values and foreach
:: when you don't need the return value. And that's what most people are
:: likely to think. Try reading perldoc perlstyle a bit... a few tidbits:
::
:: o 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.

You can do loops in the following ways:

1 C style for
2 Perl style foreach
3 for statement modifier
4 while
5 until
6 bare blocks
7 s///g
8 m//
9 goto
10 map
11 grep

Don't pick on map in void context. Could you please pick one, and make
a case against the other 10, and not just map?

:: The main point of map is the return value. The main point of foreach


:: is the iteration over an array (no return value implied).
::
:: o Avoid using grep() (or map()) or `backticks` in a void
:: context, that is, when you just throw away their
:: return values. Those functions all have return val-
:: ues, so use them. Otherwise use a foreach() loop or
:: the system() function instead.
::
:: I think this is the whole debate. Unfortunately, there's no real
:: explicit justification here.

Which makes it just the personal preference of one man, doesn't it?

:: > "Obvious" is something subjective. *YOU* might find one way of doing


:: > something more obvious than doing it another way. But that doesn't
:: > mean it's true for everyone. Could you please explain why you find
:: > map in void context so non-obvious? Do you think map in general is
:: > non-obvious, or do you only get confused when the context is void?
:: > What about other functions in void context? Are they non-obvious too?
:: > Or is it only map that's non-obvious?
::
:: Given that map and foreach do almost exactly the same thing with only
:: the desired contexts being different, it makes sense to me that one
:: would use the version one desires based on that context difference.
:: Thus, when I see map in void context, the first thought in my mind is
:: "they didn't get the return from map!".

Ah, yes. Logical. There are thousands and thousands of user defined
functions whose return value isn't collected. There are many Perl
defined functions and operators whose return value isn't collected.

Noone ever makes a fuss. But if the function of which the return
value isn't collected is called "map", hundreds of Perl programmer
brains go into overload, and the programmers start running around
like chickens without their heads. "They didn't get the return from
map! They didn't get the return from map! Keep your daughters inside!
Keep your daughters inside! The end of times in coming! The antichrist
has arrived!"

I really don't get it. map in void context isn't doing anything else
than the countless of other functions in void context that are called
because of their side effects. Yet it sparks gigabytes of discussions.

:: Then, after scrutinising the


:: map's block (as it's usually a block not an expression), I may figure
:: out that they intended to have void (e.g., only doing it for the side
:: effect). And then, if that's not the source of the problem, I can go
:: on.

But if the function wasn't called "map", but "zeebleflup", and it was
used in void context, would you get confused as well? What if it was
called "apply_this_function_over_the_elements_of_a_list"?

:: However, if they had used foreach to begin with, I might have been able


:: to skip over the code altogether knowing that "ignoring the return" is
:: exactly what was intended.

Again, why do you assume that if map was used in void context the
programmer was in error, and you have to confirm yourself it wasn't the
case, and you don't have this Pavlov reaction with other functions? What
makes map trigger this behaviour?

:: > Is there anyone who can explain why map in void context is confusing,


:: > but other functions aren't?
::
:: Simply have your code say what you mean rather than trick the virtual
:: machine into doing what you want by side effect.

If I write:

map {BLOCK} LIST;

I write *exactly* what I mean. I want to map an operation over a list.
It simple can't be named simpler.

:: In general, side


:: effects make code harder to understand.

Then you shouldn't be programming in Perl. Because in Perl, you can't
do much useful without side effects.

Darin McBride

unread,
Nov 10, 2003, 7:54:36 PM11/10/03
to
Abigail wrote:

> Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII

> September MCMXCIII in <URL:news:RKQrb.361373$6C4.143831@pd7tw1no>:


> :: Abigail wrote:
> ::
> :: > If you're going to assume the maintainer doesn't know basic concepts
> :: > of Perl, all bets are off. Then one might want to avoid hashes and
> :: > regexes too.
> ::
> :: True to a point. However, there is no cleaner way to do hashes or
> :: regexes. There is a clearer way to do map in void context: foreach.
>
> But could you give an objective reason why foreach is "clearer" than
> map (after defining what "clearer" is)? Or is it your own preference?

<sigh> I thought I had. Let me try again:

The only real difference between map and foreach is that map returns a
value, while foreach doesn't [1]. Thus, if you intend on ignoring the
return, don't create it in the first place and just use foreach.

[1] Foreach actually returns the same way any block does - the last
statement executed in the last time through the loop is the return
value. But this is not generally useful. It only makes perl more
consistant.

> What makes foreach cleaner than while? Or is while cleaner than
> foreach? Which one ought to go? Or can we have foreach, for, while,
> until, goto, and bare blocks, but not map in void context?

While vs foreach is another discussion (I wish we'd stick to a single
topic, but that's not generally possible on usenet, I suspect). If the
only data I have to work with is whether we're in void context or not,
then neither while nor foreach are different. However, they have other
strengths which would come up should we actually debate those. Again,
use whichever one makes the most readable sense.

Until vs while is easy - again, the most readable one wins. If your
assertion is positive, use while, if it is negative, use until.

And now we're really straying off the topic of this thread.

> You can do loops in the following ways:

[ If you're trying to be pedantic, you missed some. ]

> 1 C style for

Good for when you have a C-style index.

> 2 Perl style foreach

Good for when you have a perl-style index.

> 3 for statement modifier

Good when what you're trying to do is an action, and it happens to be
looped, rather than what you're trying to do is loop, and during the
loop you want to do something. Use the right loop construct for what
you're trying to do rather than try to jimmy the wrong construct into
doing what you want (which is what you have to do in most other
languages with limited choices).

> 4 while
> 5 until

These are the same as each other with the minor difference noted above
- one's assertion is positive while the other is negative. Good when
you're waiting for a condition to be false/true, and until that
happens, you want to do stuff.

> 6 bare blocks

Hmmm - there is probably a bit more needed here (redo?) I would
definitely not recommend this.

> 7 s///g

Good if you're making regex substitutions.

> 8 m//

Good if you're trying to find many of the same thing in a given string.

> 9 goto

Not generally good for looping - there is usually a better construct
for what you're trying to do.

> 10 map

Good if you're mapping one space (array) onto another space (array).

> 11 grep

Good for finding a subset of a given array.

> Don't pick on map in void context. Could you please pick one, and make
> a case against the other 10, and not just map?

Use the one that fits the job you have for it. Both map and m// are
there to create an array. If you don't want the array, I fail to see
why you'd use m//, but for map, foreach is exactly equivalent in the
void context. Use it.

> :: The main point of map is the return value. The main point of foreach
> :: is the iteration over an array (no return value implied).
> ::
> :: o Avoid using grep() (or map()) or `backticks` in a void
> :: context, that is, when you just throw away their
> :: return values. Those functions all have return val-
> :: ues, so use them. Otherwise use a foreach() loop or
> :: the system() function instead.
> ::
> :: I think this is the whole debate. Unfortunately, there's no real
> :: explicit justification here.
>
> Which makes it just the personal preference of one man, doesn't it?

No - it means that the perlstyle authors (who are probably more
proficient in perl than the both of us put together) thought this would
be obvious and unneeding of justification.

> :: Given that map and foreach do almost exactly the same thing with only
> :: the desired contexts being different, it makes sense to me that one
> :: would use the version one desires based on that context difference.
> :: Thus, when I see map in void context, the first thought in my mind is
> :: "they didn't get the return from map!".
>
> Ah, yes. Logical. There are thousands and thousands of user defined
> functions whose return value isn't collected. There are many Perl
> defined functions and operators whose return value isn't collected.
>
> Noone ever makes a fuss. But if the function of which the return

I do. If there are two user defined functions that do exactly the same
thing, but one allocates and returns an array, and the other does not
but has the same desired side effects, I would expect people to use the
appropriate one depending on whether they want the array returned or
not. I don't see any difference.

> value isn't collected is called "map", hundreds of Perl programmer
> brains go into overload, and the programmers start running around
> like chickens without their heads. "They didn't get the return from
> map! They didn't get the return from map! Keep your daughters inside!
> Keep your daughters inside! The end of times in coming! The antichrist
> has arrived!"

I'm not sure that the Six Degrees of Godwin game would have anticipated
this as "legitimate topic drift".

> I really don't get it. map in void context isn't doing anything else
> than the countless of other functions in void context that are called
> because of their side effects. Yet it sparks gigabytes of discussions.

Only because there is an exact duplicate of map functionally that is
there for void context.

> :: Then, after scrutinising the
> :: map's block (as it's usually a block not an expression), I may figure
> :: out that they intended to have void (e.g., only doing it for the side
> :: effect). And then, if that's not the source of the problem, I can go
> :: on.
>
> But if the function wasn't called "map", but "zeebleflup", and it was
> used in void context, would you get confused as well? What if it was
> called "apply_this_function_over_the_elements_of_a_list"?

Well, if it were called "zeebleflup", I'd be looking for zeebleflup's
definition to understand what the heck it is, and why someone thought
that this was a brilliant name to give a function.

You see, I'm not worried about some "map" crusade. I'm looking for
readability. I'd be just as curious about why someone calls map in
void context as someone calling $my_circle->get_radius() in void
context. If someone was looking at the return to a function that
obviously shouldn't have one, I'd be just as curious (although I can't
think of an example function name that would cause me to think this
offhand).

> :: However, if they had used foreach to begin with, I might have been
> :: able to skip over the code altogether knowing that "ignoring the
> :: return" is exactly what was intended.
>
> Again, why do you assume that if map was used in void context the
> programmer was in error, and you have to confirm yourself it wasn't the
> case, and you don't have this Pavlov reaction with other functions? What
> makes map trigger this behaviour?

Who said I don't have this reaction to any other function? Perhaps
some of your previous sparring partners are that way, but you paint me
unfairly with the same brush. If I were into the same ad hominum style
debate, I'd start wondering about your knee-jerk reactions...

> :: Simply have your code say what you mean rather than trick the virtual
> :: machine into doing what you want by side effect.
>
> If I write:
>
> map {BLOCK} LIST;
>
> I write *exactly* what I mean. I want to map an operation over a list.
> It simple can't be named simpler.

If we were writing LISP where that's what map means, that's fine. But
in perl, if you want to "map an operation over a list", that's called
"foreach".

> :: In general, side
> :: effects make code harder to understand.
>
> Then you shouldn't be programming in Perl. Because in Perl, you can't
> do much useful without side effects.

Hmmm... I dunno - I've managed to do a lot of useful stuff without side
effects in perl.

Tassilo v. Parseval

unread,
Nov 11, 2003, 3:12:50 AM11/11/03
to
Also sprach Darin McBride:

> Abigail wrote:
>
>> Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII
>> September MCMXCIII in <URL:news:FRCrb.356754$pl3.261426@pd7tw3no>:
>> __ Abigail wrote:
>> __
>> __ No, you're right. I suppose you overlooked the "that's the concept"
>> __ part of that paragraph. Context rules in perl. But that doesn't mean
>> __ that context rules in the maintainer's head when trying to decipher
>> __ what was written.
>>
>> If you're going to assume the maintainer doesn't know basic concepts
>> of Perl, all bets are off. Then one might want to avoid hashes and
>> regexes too.

[...]

> The main point of map is the return value. The main point of foreach
> is the iteration over an array (no return value implied).
>
> o Avoid using grep() (or map()) or `backticks` in a void
> context, that is, when you just throw away their
> return values. Those functions all have return val-
> ues, so use them. Otherwise use a foreach() loop or
> the system() function instead.
>
> I think this is the whole debate. Unfortunately, there's no real
> explicit justification here.

The mentioning of map() needs to be scratched from perlstyle.pod as it's
no longer true. Forgot to include that in my map-patch.

Much easier. This

if (items) {

had to become

if (items && gimme != G_VOID) {

If the condition evaluates to false, about 15 lines of code are skipped
and pp_mapwhile (the core of a map() statement) becomes quite a simple
operation.

Which however doesn't change the fact that foreach is faster. The
difference is marginal for 'map EXPR, LIST' (6% in favour of for).
Strangely enough, map is disproportionally slower in the 'map BLOCK
LIST' case...around 50%.

There's also a different syntax involved:

map BLOCK LIST
map EXPR, LIST

versus

for LIST BLOCK
STATEMENT for LIST

Particularly, you can change from EXPR to BLOCK without changing a lot
in your code when using map().

>> Is there anyone who can explain why map in void context is confusing,
>> but other functions aren't?
>
> Simply have your code say what you mean rather than trick the virtual
> machine into doing what you want by side effect. In general, side
> effects make code harder to understand.

Depends on the standpoint. When I began with Perl, the return value of
map() was the side-effect (side-effect in the way that I didn't use this
feature). I was familiar with the idea of mapping a function to members
of a list however. That was before I learned about statement-modifiers
therefore using map() in void context was the natural choice for me (it
no longer is to this extent since these statement-modifiers somewhat
changed my habits).

Anyway, you can't make assumptions about how a programmer thinks. Or at
least you can't expect to always make the right ones.

Ben Morrow

unread,
Nov 11, 2003, 3:52:48 AM11/11/03
to

tassilo....@post.rwth-aachen.de wrote:
> Strangely enough, map is disproportionally slower in the 'map BLOCK
> LIST' case...around 50%.

Presumably this is the overhead involved in setting up and tearing
down a BLOCK?

Ben

Tassilo v. Parseval

unread,
Nov 11, 2003, 4:09:54 AM11/11/03
to
Also sprach Ben Morrow:

> tassilo....@post.rwth-aachen.de wrote:
>> Strangely enough, map is disproportionally slower in the 'map BLOCK
>> LIST' case...around 50%.
>
> Presumably this is the overhead involved in setting up and tearing
> down a BLOCK?

Yes, most certainly. But I would expect a similar overhead when using
blocks and foreach. Maybe it has something to do with the callback
nature of BLOCK in the map() case. Afterall, map() is a function while
foreach is not.

Calle Dybedahl

unread,
Nov 11, 2003, 6:08:32 AM11/11/03
to
>>>>> "Darin" == Darin McBride <dmcb...@naboo.to.org.no.spam.for.me> writes:

> The only real difference between map and foreach is that map returns a
> value, while foreach doesn't [1]. Thus, if you intend on ignoring the
> return, don't create it in the first place and just use foreach.

But map *doesn't* create a list to return when you use it in a void
context. So the choice between map or foreach does become one of
simple personal preference.

> No - it means that the perlstyle authors (who are probably more
> proficient in perl than the both of us put together) thought this
> would be obvious and unneeding of justification.

Argumentation by appeal to authority is pretty weak. That you're also
wrong only makes it worse, Abigail knows at least as much about Perl
as whoever wrote perlstyle (TomC probably, since it doesn't have any
author information in it).
--
Calle Dybedahl <ca...@lysator.liu.se>
"I like darkness, because it shows us light" -- Victoria McManus

Tassilo v. Parseval

unread,
Nov 11, 2003, 7:03:04 AM11/11/03
to
Also sprach Calle Dybedahl:

>>>>>> "Darin" == Darin McBride <dmcb...@naboo.to.org.no.spam.for.me> writes:

>> No - it means that the perlstyle authors (who are probably more
>> proficient in perl than the both of us put together) thought this
>> would be obvious and unneeding of justification.
>
> Argumentation by appeal to authority is pretty weak. That you're also
> wrong only makes it worse, Abigail knows at least as much about Perl
> as whoever wrote perlstyle (TomC probably, since it doesn't have any
> author information in it).

Minor correction: as whoever wrote perl. :-)

Abigail

unread,
Nov 11, 2003, 7:46:30 AM11/11/03
to
Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIV
September MCMXCIII in <URL:news:grWrb.362981$pl3.319787@pd7tw3no>:
@@ Abigail wrote:
@@
@@ > Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIII
@@ > September MCMXCIII in <URL:news:RKQrb.361373$6C4.143831@pd7tw1no>:
@@ > :: Abigail wrote:
@@ > ::
@@ > :: > If you're going to assume the maintainer doesn't know basic concepts
@@ > :: > of Perl, all bets are off. Then one might want to avoid hashes and
@@ > :: > regexes too.
@@ > ::
@@ > :: True to a point. However, there is no cleaner way to do hashes or
@@ > :: regexes. There is a clearer way to do map in void context: foreach.
@@ >
@@ > But could you give an objective reason why foreach is "clearer" than
@@ > map (after defining what "clearer" is)? Or is it your own preference?
@@
@@ <sigh> I thought I had. Let me try again:
@@
@@ The only real difference between map and foreach is that map returns a
@@ value, while foreach doesn't [1]. Thus, if you intend on ignoring the
@@ return, don't create it in the first place and just use foreach.

map in void context has never returned anything. No function in void
context has ever returned anything. How could it - if it returned
something, it couldn't have been in void context. Now, up to 2 versions
ago, map created a temporary list, even if it didn't need it. That has
now been fixed.

@@ [1] Foreach actually returns the same way any block does - the last
@@ statement executed in the last time through the loop is the return
@@ value. But this is not generally useful. It only makes perl more
@@ consistant.
@@
@@ > What makes foreach cleaner than while? Or is while cleaner than
@@ > foreach? Which one ought to go? Or can we have foreach, for, while,
@@ > until, goto, and bare blocks, but not map in void context?
@@
@@ While vs foreach is another discussion (I wish we'd stick to a single
@@ topic, but that's not generally possible on usenet, I suspect). If the
@@ only data I have to work with is whether we're in void context or not,
@@ then neither while nor foreach are different. However, they have other
@@ strengths which would come up should we actually debate those. Again,
@@ use whichever one makes the most readable sense.

The latter is a good remark. That's why I sometimes use while, sometimes
for/foreach, and sometimes map in void context. See, there is a difference
how you read them:

map ACTION DATA;
for DATA ACTION;

If I want to have the focus on the action, I prefer map. If I want to
focus on the action, I prefer for. But focus isn't the only thing that's
important for readability. I prefer shorter things before larger things.
So, if my block is large, I'll prefer to use for. But if the data is
coming from a long and complex expression, I'll favour map.

@@ Until vs while is easy - again, the most readable one wins. If your
@@ assertion is positive, use while, if it is negative, use until.

So, you decide on for vs while and while vs until on a case by case
basis. That's good. However, you dismiss map right away.

@@ > :: The main point of map is the return value. The main point of foreach
@@ > :: is the iteration over an array (no return value implied).
@@ > ::
@@ > :: o Avoid using grep() (or map()) or `backticks` in a void
@@ > :: context, that is, when you just throw away their
@@ > :: return values. Those functions all have return val-
@@ > :: ues, so use them. Otherwise use a foreach() loop or
@@ > :: the system() function instead.
@@ > ::
@@ > :: I think this is the whole debate. Unfortunately, there's no real
@@ > :: explicit justification here.
@@ >
@@ > Which makes it just the personal preference of one man, doesn't it?
@@
@@ No - it means that the perlstyle authors (who are probably more
@@ proficient in perl than the both of us put together) thought this would
@@ be obvious and unneeding of justification.

Well, apparently it isn't obvious, and in dire need of a justification.
But I don't think Larry is going to do that. Some fragments of perlstyle:

Larry has his reasons for each of these things, but he
doesn't claim that everyone else's mind works the same as
his does.

o 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.

See? Larry thinks that it's important that you mention the main point
first. So, if the main point is the action, not the data it acts upon,
you would write:

map ACTION DATA;

and not

for DATA ACTION;

@@ > :: Given that map and foreach do almost exactly the same thing with only
@@ > :: the desired contexts being different, it makes sense to me that one
@@ > :: would use the version one desires based on that context difference.
@@ > :: Thus, when I see map in void context, the first thought in my mind is
@@ > :: "they didn't get the return from map!".
@@ >
@@ > Ah, yes. Logical. There are thousands and thousands of user defined
@@ > functions whose return value isn't collected. There are many Perl
@@ > defined functions and operators whose return value isn't collected.
@@ >
@@ > Noone ever makes a fuss. But if the function of which the return
@@
@@ I do. If there are two user defined functions that do exactly the same
@@ thing, but one allocates and returns an array, and the other does not
@@ but has the same desired side effects, I would expect people to use the
@@ appropriate one depending on whether they want the array returned or
@@ not. I don't see any difference.

There are two points against that:

1) map in void context *doesn't* allocated an array whose
values remained unused.
2) it goes against all ideas of encapsulation. If in order
to use a module, I would first have to study the implementation
of its functions, why bother? I could write my own. But you
go further, you require people to first have studied the
implementation of perl before they can pick the "right way".
I presume you have carefully studied all the libraries Perl
links in as well?

@@
@@ > value isn't collected is called "map", hundreds of Perl programmer
@@ > brains go into overload, and the programmers start running around
@@ > like chickens without their heads. "They didn't get the return from
@@ > map! They didn't get the return from map! Keep your daughters inside!
@@ > Keep your daughters inside! The end of times in coming! The antichrist
@@ > has arrived!"
@@
@@ I'm not sure that the Six Degrees of Godwin game would have anticipated
@@ this as "legitimate topic drift".
@@
@@ > I really don't get it. map in void context isn't doing anything else
@@ > than the countless of other functions in void context that are called
@@ > because of their side effects. Yet it sparks gigabytes of discussions.
@@
@@ Only because there is an exact duplicate of map functionally that is
@@ there for void context.

There is also an exact duplicate of 'unless' (which even takes less
characters to type). Should 'unless' be avoided as well? The functionality
of while() can also exactly be duplicated with bare blocks. Should
while() be avoided? If the answers are 'no', then why is it so bad
there's another way of doing a map in void context?

@@
@@ > :: In general, side
@@ > :: effects make code harder to understand.
@@ >
@@ > Then you shouldn't be programming in Perl. Because in Perl, you can't
@@ > do much useful without side effects.
@@
@@ Hmmm... I dunno - I've managed to do a lot of useful stuff without side
@@ effects in perl.


Really? Could you show some code? Remember, assignment and print are
only useful because of their side effects.

Abigail
--
perl -we 'print split /(?=(.*))/s => "Just another Perl Hacker\n";'

Darin McBride

unread,
Nov 11, 2003, 11:03:28 AM11/11/03
to
Abigail wrote:

> Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIV
> September MCMXCIII in <URL:news:grWrb.362981$pl3.319787@pd7tw3no>:
> @@ Abigail wrote:
> @@

> @@ > But could you give an objective reason why foreach is "clearer" than
> @@ > map (after defining what "clearer" is)? Or is it your own preference?
> @@
> @@ <sigh> I thought I had. Let me try again:
> @@
> @@ The only real difference between map and foreach is that map returns a
> @@ value, while foreach doesn't [1]. Thus, if you intend on ignoring the
> @@ return, don't create it in the first place and just use foreach.
>
> map in void context has never returned anything. No function in void
> context has ever returned anything. How could it - if it returned
> something, it couldn't have been in void context. Now, up to 2 versions
> ago, map created a temporary list, even if it didn't need it. That has
> now been fixed.

sub foo()
{
return qw(this is a small array);
}

foo();

And you're saying something in void context doesn't return anything?
No, I think perlstyle is right - map returns something (or at least it
did). The VM cleans it up by deallocating it immediately (or at the
end of the calling block, I'm not exactly sure when). But it is
returned.

Now with the map "fix", it won't create the array. And thus it won't
return anything. However, given that the difference between map and
foreach was solely that return difference, I don't see a point behind
the patch.

> @@ > What makes foreach cleaner than while? Or is while cleaner than
> @@ > foreach? Which one ought to go? Or can we have foreach, for, while,
> @@ > until, goto, and bare blocks, but not map in void context?
> @@
> @@ While vs foreach is another discussion (I wish we'd stick to a single
> @@ topic, but that's not generally possible on usenet, I suspect). If
> the
> @@ only data I have to work with is whether we're in void context or not,
> @@ then neither while nor foreach are different. However, they have
> other
> @@ strengths which would come up should we actually debate those. Again,
> @@ use whichever one makes the most readable sense.
>
> The latter is a good remark. That's why I sometimes use while, sometimes
> for/foreach, and sometimes map in void context. See, there is a difference
> how you read them:
>
> map ACTION DATA;
> for DATA ACTION;
>
> If I want to have the focus on the action, I prefer map. If I want to
> focus on the action, I prefer for. But focus isn't the only thing that's
> important for readability. I prefer shorter things before larger things.
> So, if my block is large, I'll prefer to use for. But if the data is
> coming from a long and complex expression, I'll favour map.

I see what you're saying - unfortunately, to me the simple perldoc on
map makes the void context of map counterintuitive: "... and returns
the list value composed of ..." And thus, those of us who do not have
any LISP background, have a certain expectation that you're using the
function according to the docs...

> @@ Until vs while is easy - again, the most readable one wins. If your
> @@ assertion is positive, use while, if it is negative, use until.
>
> So, you decide on for vs while and while vs until on a case by case
> basis. That's good. However, you dismiss map right away.

No - I use map more than I use for or foreach. But that's primarily
because I am mapping problem spaces from one space to another more than
I am simply looping through constructs.

> @@ > :: o Avoid using grep() (or map()) or `backticks` in a void
> @@ > :: context, that is, when you just throw away their
> @@ > :: return values. Those functions all have return val-
> @@ > :: ues, so use them. Otherwise use a foreach() loop or
> @@ > :: the system() function instead.
> @@ > ::
> @@ > :: I think this is the whole debate. Unfortunately, there's no real
> @@ > :: explicit justification here.
> @@ >
> @@ > Which makes it just the personal preference of one man, doesn't it?
> @@
> @@ No - it means that the perlstyle authors (who are probably more
> @@ proficient in perl than the both of us put together) thought this
> would
> @@ be obvious and unneeding of justification.
>
> Well, apparently it isn't obvious, and in dire need of a justification.
> But I don't think Larry is going to do that. Some fragments of perlstyle:
>
> Larry has his reasons for each of these things, but he
> doesn't claim that everyone else's mind works the same as
> his does.

And Larry probably has better knowledge of perl than the rest of us.
Being a linguist rather than a purist, he doesn't force us to do things
his way, but that doesn't mean his thoughts aren't likely to be better.

[ first element from perlstyle under the above quote deleted for space
reasons... this is getting too damned long already ;-> ]

> See? Larry thinks that it's important that you mention the main point
> first. So, if the main point is the action, not the data it acts upon,
> you would write:
>
> map ACTION DATA;
>
> and not
>
> for DATA ACTION;

None of the examples are ignoring return codes, which is also mentioned
explicitly later on in the perlstyle document (as I quoted earlier).

> @@ > Ah, yes. Logical. There are thousands and thousands of user defined
> @@ > functions whose return value isn't collected. There are many Perl
> @@ > defined functions and operators whose return value isn't collected.
> @@ >
> @@ > Noone ever makes a fuss. But if the function of which the return
> @@
> @@ I do. If there are two user defined functions that do exactly the
> same
> @@ thing, but one allocates and returns an array, and the other does not
> @@ but has the same desired side effects, I would expect people to use
> the
> @@ appropriate one depending on whether they want the array returned or
> @@ not. I don't see any difference.
>
> There are two points against that:
>
> 1) map in void context *doesn't* allocated an array whose
> values remained unused.

Perhaps if you work exclusively with perl 5.8+, that might be true.
However, this doesn't work for two points:
1a) Some of us still work in shops that haven't upgraded from 5.6 yet
(no matter how hard I've pushed)
1b) map still allocates that array *conceptually* in the reader's
mind, even if no allocation actually takes place on the physical
machine.

> 2) it goes against all ideas of encapsulation. If in order
> to use a module, I would first have to study the implementation
> of its functions, why bother? I could write my own. But you
> go further, you require people to first have studied the
> implementation of perl before they can pick the "right way".
> I presume you have carefully studied all the libraries Perl
> links in as well?

Who said anything about studying the implementation? I haven't studied
the implementation of map or for either - only their docs. I *would*
expect that you would first study the perldoc on the module before
trying to use it... and if it documented two functions doing the same
thing, one that allocated and returned another object (whether ARRAY,
HASH or real object), and another that did exactly the same thing
without that allocation and return, then the point still stands.

> @@ > I really don't get it. map in void context isn't doing anything else
> @@ > than the countless of other functions in void context that are called
> @@ > because of their side effects. Yet it sparks gigabytes of
> discussions. @@
> @@ Only because there is an exact duplicate of map functionally that is
> @@ there for void context.
>
> There is also an exact duplicate of 'unless' (which even takes less
> characters to type). Should 'unless' be avoided as well? The functionality

Um, where did I say that? Are you fond of putting words in my mouth?
This is the same as the while/until comparison above: use if for
positive assertions, unless for negative assertions. "unless ($foo) {}"
is way more readable than "if (not $foo) {}". Use the right tool for
the job.

> of while() can also exactly be duplicated with bare blocks. Should
> while() be avoided? If the answers are 'no', then why is it so bad
> there's another way of doing a map in void context?

Who said it was bad? I said it was goodness - so use the right tool
for the job!

> @@ > Then you shouldn't be programming in Perl. Because in Perl, you can't
> @@ > do much useful without side effects.
> @@
> @@ Hmmm... I dunno - I've managed to do a lot of useful stuff without
> side
> @@ effects in perl.
>
> Really? Could you show some code? Remember, assignment and print are
> only useful because of their side effects.

I respectfully must disagree with your definition of "side effects".

Darin McBride

unread,
Nov 11, 2003, 11:05:47 AM11/11/03
to
Calle Dybedahl wrote:

>>>>>> "Darin" == Darin McBride <dmcb...@naboo.to.org.no.spam.for.me>
>>>>>> writes:
>
>> The only real difference between map and foreach is that map returns a
>> value, while foreach doesn't [1]. Thus, if you intend on ignoring the
>> return, don't create it in the first place and just use foreach.
>
> But map *doesn't* create a list to return when you use it in a void
> context. So the choice between map or foreach does become one of
> simple personal preference.

Which version of perl are you using? I'm still stuck on 5.6.0 and
5.6.1 at work.

>> No - it means that the perlstyle authors (who are probably more
>> proficient in perl than the both of us put together) thought this
>> would be obvious and unneeding of justification.
>
> Argumentation by appeal to authority is pretty weak. That you're also
> wrong only makes it worse, Abigail knows at least as much about Perl
> as whoever wrote perlstyle (TomC probably, since it doesn't have any
> author information in it).

Knowing perl and knowing perl style is not necessarily the same thing.
I'm not debating Abigail's knowledge of perl (as I believe mine to be
relatively extensive as well). But we still disagree on calling
functions that document array returns in void context when an
equivalent function exists that documents that there is no return (or
fails to document a return).

Ben Morrow

unread,
Nov 11, 2003, 12:00:12 PM11/11/03
to

Darin McBride <dmcb...@naboo.to.org.no.spam.for.me> wrote:

> Abigail wrote:
> > map in void context has never returned anything. No function in void
> > context has ever returned anything. How could it - if it returned
> > something, it couldn't have been in void context. Now, up to 2 versions
> > ago, map created a temporary list, even if it didn't need it. That has
> > now been fixed.
>
> sub foo()
> {
> return qw(this is a small array);
> }
>
> foo();
>
> And you're saying something in void context doesn't return anything?

my $x = foo();

And you're saying that this returns a list?

> However, given that the difference between map and
> foreach was solely that return difference, I don't see a point behind
> the patch.

I don't think that is 'given', at least not by Abigail. Hence the
argument...

> > There are two points against that:
> >
> > 1) map in void context *doesn't* allocated an array whose
> > values remained unused.
>
> Perhaps if you work exclusively with perl 5.8+, that might be true.
> However, this doesn't work for two points:
> 1a) Some of us still work in shops that haven't upgraded from 5.6 yet
> (no matter how hard I've pushed)
> 1b) map still allocates that array *conceptually* in the reader's
> mind, even if no allocation actually takes place on the physical
> machine.

Err, no... at least, not in my mind; any more than

my $x = 5;

conceptually allocates a scalar return value. As pointed out above, a
function called in void context *never* conceptually allocates a
return value. The fact that map in fact did so was a bug.

> > Really? Could you show some code? Remember, assignment and print are
> > only useful because of their side effects.
>
> I respectfully must disagree with your definition of "side effects".

About the only objective definition of 'side-effect' is 'any effect a
function has other than its return value'. Yes, this is Lisp-ish. No,
that does not make it wrong.

Ben

--
. | .
\ / The clueometer is reading zero.
. .
__ <-----@ __ b...@morrow.me.uk

Abigail

unread,
Nov 11, 2003, 12:01:35 PM11/11/03
to
Darin McBride (dmcb...@naboo.to.org.no.spam.for.me) wrote on MMMDCCXXIV
September MCMXCIII in <URL:news:kL7sb.370510$9l5.366840@pd7tw2no>:
//
// I see what you're saying - unfortunately, to me the simple perldoc on
// map makes the void context of map counterintuitive: "... and returns
// the list value composed of ..." And thus, those of us who do not have
// any LISP background, have a certain expectation that you're using the
// function according to the docs...


But even without a LISP background, you must know it's good to read
past the first sentence. The first two sentences are (and this is from
the 5.6.0 doc):

Evaluates the BLOCK or EXPR for each element of
LIST (locally setting `$_' to each element) and
returns the list value composed of the results of
each such evaluation. In scalar context, returns
the total number of elements so generated.

Considering that void context is a special version of scalar context,
the notion that map in void context would return a list *cannot* be
based on the documentation. At best, you would be discarding a *single*
value - just like do you when using print in void context.


// > @@ Until vs while is easy - again, the most readable one wins. If your
// > @@ assertion is positive, use while, if it is negative, use until.
// >
// > So, you decide on for vs while and while vs until on a case by case
// > basis. That's good. However, you dismiss map right away.
//
// No - I use map more than I use for or foreach. But that's primarily
// because I am mapping problem spaces from one space to another more than
// I am simply looping through constructs.


Well, we were discussing loops where we aren't interested in return values.
That is, where you could use map in void context.


// > @@ > :: o Avoid using grep() (or map()) or `backticks` in a void
// > @@ > :: context, that is, when you just throw away their
// > @@ > :: return values. Those functions all have return val-
// > @@ > :: ues, so use them. Otherwise use a foreach() loop or
// > @@ > :: the system() function instead.
// > @@ > ::
// > @@ > :: I think this is the whole debate. Unfortunately, there's no real
// > @@ > :: explicit justification here.
// > @@ >
// > @@ > Which makes it just the personal preference of one man, doesn't it?
// > @@
// > @@ No - it means that the perlstyle authors (who are probably more
// > @@ proficient in perl than the both of us put together) thought this
// > would
// > @@ be obvious and unneeding of justification.
// >
// > Well, apparently it isn't obvious, and in dire need of a justification.
// > But I don't think Larry is going to do that. Some fragments of perlstyle:
// >
// > Larry has his reasons for each of these things, but he
// > doesn't claim that everyone else's mind works the same as
// > his does.
//
// And Larry probably has better knowledge of perl than the rest of us.
// Being a linguist rather than a purist, he doesn't force us to do things
// his way, but that doesn't mean his thoughts aren't likely to be better.


I've heard Larry saying he seldomly uses 'strict' (and he had the code to
prove it). Damian, another rather well known Perl programmer hardly uses
'strict' either. Does that knowledge now make you stop using 'strict'? Or
do you form your own opinion on that? I use map in void context because
*I* think it's ok, I'm not going to hide myself behind someone who might
be a better programmer.


// Who said anything about studying the implementation? I haven't studied
// the implementation of map or for either - only their docs. I *would*
// expect that you would first study the perldoc on the module before
// trying to use it... and if it documented two functions doing the same
// thing, one that allocated and returned another object (whether ARRAY,
// HASH or real object), and another that did exactly the same thing
// without that allocation and return, then the point still stands.


Here's the 5.6.0 (because you still use that) doc about map. Could you
point out where in the doc it says it's allocating an array when map is
used in void context?


map EXPR,LIST
Evaluates the BLOCK or EXPR for each element of
LIST (locally setting `$_' to each element) and
returns the list value composed of the results of
each such evaluation. In scalar context, returns
the total number of elements so generated. Evalu-
ates BLOCK or EXPR in list context, so each ele-
ment of LIST may produce zero, one, or more ele-
ments in the returned value.

@chars = map(chr, @nums);

translates a list of numbers to the corresponding
characters. And

%hash = map { getkey($_) => $_ } @array;

is just a funny way to write

%hash = ();
foreach $_ (@array) {
$hash{getkey($_)} = $_;
}

Note that, because `$_' is a reference into the
list value, it can be used to modify the elements
of the array. While this is useful and supported,
it can cause bizarre results if the LIST is not a
named array. Using a regular `foreach' loop for
this purpose would be clearer in most cases. See
also the grep entry elsewhere in this document for
an array composed of those items of the original
list for which the BLOCK or EXPR evaluates to
true.


// > @@ > Then you shouldn't be programming in Perl. Because in Perl, you can't
// > @@ > do much useful without side effects.
// > @@
// > @@ Hmmm... I dunno - I've managed to do a lot of useful stuff without
// > side
// > @@ effects in perl.
// >
// > Really? Could you show some code? Remember, assignment and print are
// > only useful because of their side effects.
//
// I respectfully must disagree with your definition of "side effects".


A language construct that modifies the state of the system. The most
common side-effects are assignment, input and output. A language without
side-effects is purely-functional - execution consists of the evaluation
of an expression and all subexpressions are referentially transparent.

http://foldoc.doc.ic.ac.uk/foldoc/foldoc.cgi?query=side+effect&action=Search


Now, you can make up your own definitions, but that's leading nowhere.


Abigail
--
perl -le 's[$,][join$,,(split$,,($!=85))[(q[0006143730380126152532042307].
q[41342211132019313505])=~m[..]g]]e and y[yIbp][HJkP] and print'

Steve Grazzini

unread,
Nov 11, 2003, 1:24:48 PM11/11/03
to
Ben Morrow <use...@morrow.me.uk> wrote:
> Darin McBride <dmcb...@naboo.to.org.no.spam.for.me> wrote:
>> Abigail wrote:
>> > map in void context has never returned anything. No function in void
>> > context has ever returned anything.
>>
>> sub foo()
>> {
>> return qw(this is a small array);
>> }
>>
>> foo();
>>
>> And you're saying something in void context doesn't return anything?
>
> my $x = foo();
>
> And you're saying that this returns a list?

I can't answer for Darin, but I think it does return a list.

% perl -Dts -le 'sub f { "one", "two", "three" } f()'

EXECUTING...

=>
(-e:0) enter
=>
(-e:0) nextstate
=>
(-e:1) pushmark
=> *
(-e:1) gv(main::f)
=> * GV()
(-e:1) entersub
=>
(-e:1) nextstate
=>
(-e:1) pushmark
=> *
(-e:1) const(PV("one"\0))
=> * PV("one"\0)
(-e:1) const(PV("two"\0))
=> * PV("one"\0) PV("two"\0)
(-e:1) const(PV("three"\0))
=> * PV("one"\0) PV("two"\0) PV("three"\0)
(-e:1) list
=> PV("three"\0)
(-e:1) leavesub
=> PV("three"\0)
(-e:1) leave

This is void context, of course, and commas instead of qw(), but it
works just like your example. The subroutine returns a list and a
list in void or scalar context evaluates [pp.c: pp_list] to its last
element.

I suppose it would also be possible to say that the subroutine returns
the *result* of evaluating a list in void context. And likewise, that
this one returns the result of evaluating an array in scalar context:

% perl -Ds -le 'sub f { @INC } scalar f()'

But I'd rather say that this returns an array.

The more common explanation -- that the comma operator in scalar
context works "like it does in C", i.e. evaluating and discarding its
LHS and returning its RHS -- also fits the result, but it's not quite
as accurate.

--
Steve

Roy Johnson

unread,
Nov 11, 2003, 1:37:23 PM11/11/03
to
Ben Morrow <use...@morrow.me.uk> wrote in message news:<bonpl5$4cm$1...@wisteria.csv.warwick.ac.uk>...

> It also gives a specific use for map in void context: to call a
> function in list context but discard the result.

Which is another thing that smacks of bad practice.

Ben Morrow

unread,
Nov 11, 2003, 6:18:22 PM11/11/03
to

Steve Grazzini <gr...@pobox.com> wrote:
> Ben Morrow <use...@morrow.me.uk> wrote:
> > Darin McBride <dmcb...@naboo.to.org.no.spam.for.me> wrote:
> >> Abigail wrote:
> >> > map in void context has never returned anything. No function in void
> >> > context has ever returned anything.
> >>
> >> sub foo()
> >> {
> >> return qw(this is a small array);
> >> }
> >>
> >> foo();
> >>
> >> And you're saying something in void context doesn't return anything?
> >
> > my $x = foo();
> >
> > And you're saying that this returns a list?
>
> I can't answer for Darin, but I think it does return a list.
>
> % perl -Dts -le 'sub f { "one", "two", "three" } f()'
<snip>

> This is void context, of course, and commas instead of qw(), but it
> works just like your example. The subroutine returns a list and a
> list in void or scalar context evaluates [pp.c: pp_list] to its last
> element.

I'm afraid I can't really follow that: which line is supposed to be
'the return value'?; but it makes no difference anyway. We are talking
about the conceptual return value, ie. about what Perl returns; if
perl in fact builds a list only to discard all but the last element
this is a bug, like the one in map was.

> I suppose it would also be possible to say that the subroutine returns
> the *result* of evaluating a list in void context. And likewise, that
> this one returns the result of evaluating an array in scalar context:
>
> % perl -Ds -le 'sub f { @INC } scalar f()'
>
> But I'd rather say that this returns an array.

But that would be quite wrong. In Perl, a function *cannot* return an
array, only a list if in list context or a scalar if in scalar. For
instance, what about this

% perl -le'sub f { caller } print scalar f'

? Would you say this returns 'the caller function', which is then
evaluated in scalar context? It certainly doesn't return a list:
according to you, the result of 'evaluating a list in scalar context'
is its last element, which is not what is returned.

In fact, as Randal keeps saying, there is *no such thing* as 'a list
in scalar context'.

> The more common explanation -- that the comma operator in scalar
> context works "like it does in C", i.e. evaluating and discarding its
> LHS and returning its RHS -- also fits the result, but it's not quite
> as accurate.

OK, the comma operator in scalar context builds a list and then
discards all but the last element. Just out of interest (my perl isn't
built with DEBUGGING), what does this do

% perl -Dts -le'scalar (1, 2, 3)'

? Is the whole list built, or are the values discarded as it goes
along?

Ben

--
"The Earth is degenerating these days. Bribery and corruption abound.
Children no longer mind their parents, every man wants to write a book,
and it is evident that the end of the world is fast approaching."
-Assyrian stone tablet, c.2800 BC b...@morrow.me.uk

Steve Grazzini

unread,
Nov 11, 2003, 10:47:05 PM11/11/03
to
Ben Morrow <use...@morrow.me.uk> wrote:

> Steve Grazzini <gr...@pobox.com> wrote:
>> I suppose it would also be possible to say that the subroutine
>> returns the *result* of evaluating a list in void context. And
>> likewise, that this one returns the result of evaluating an array
>> in scalar context:
>>
>> % perl -Ds -le 'sub f { @INC } scalar f()'
>>
>> But I'd rather say that this returns an array.
>
> But that would be quite wrong. In Perl, a function *cannot* return
> an array, only a list if in list context or a scalar if in scalar.

That's true, of course. I think I got it right earlier: f() returns
the result of evaluating @INC in scalar context when it's called in
scalar context, and the result of evaluating @INC in list context when
it's called in list context. Condensing this to "f() returns @INC" is
less precise, but maybe it's close enough to be useful, assuming that
we all know you can't *really* return an array from a subroutine and
do "push foo(), $elt" or whatever.

> For instance, what about this
>
> % perl -le'sub f { caller } print scalar f'
>
> ? Would you say this returns 'the caller function', which is then
> evaluated in scalar context?

Well, no. That would be silly. :-)

> It certainly doesn't return a list:

It certainly doesn't!

> according to you, the result of 'evaluating a list in scalar context'
> is its last element, which is not what is returned.

That's because (as you must know) caller() doesn't return a list in
scalar context. Since there's no list, this doesn't have anything
to do with the behavior of a list in scalar context.

> In fact, as Randal keeps saying, there is *no such thing* as 'a list
> in scalar context'.

That's a simplification, too. It's probably the best thing to tell
people who are trying to figure out what a built-in does in scalar
context based on what it does in list context. But it's not the whole
story -- perldata explains this more accurately:

If you evaluate an array in scalar context, it returns the length
of the array. (Note that this is not true of lists, which return
the last value, like the C comma operator, nor of built-in functions,
which return whatever they feel like returning.)

> OK, the comma operator in scalar context builds a list and then
> discards all but the last element. Just out of interest (my perl
> isn't built with DEBUGGING), what does this do
>
> % perl -Dts -le'scalar (1, 2, 3)'
>
> ? Is the whole list built, or are the values discarded as it goes
> along?

Neither. :-)

Here the compiler knows that the potential list is in scalar context,
and it puts the "1" and "2" in void context, since they're just going
to be discarded. Constants in void context can be optimized away
(i.e. discarded at compile-time) and that's what happens here.

This is the zen-like "There Is No List..." scenario from the FAQ:

As a side note, there's no such thing as a list in scalar con-
text. When you say

$scalar = (2, 5, 7, 9);

you're using the comma operator in scalar context, so it uses
the scalar comma operator. There never was a list there at
all! This causes the last value to be returned: 9.

And perlfunc:

A named array in scalar context is quite different from what would
at first glance appear to be a list in scalar context. You can't
get a list like "(1,2,3)" into being in scalar context, because the
compiler knows the context at compile time. It would generate the
scalar comma operator there, not the list construction version of
the comma. That means it was never a list to start with.

And they're correct, more or less, for the examples they give. But the
bit about the "scalar comma operator" seems to be misguided. If any of
the earlier elements of those lists were variables, a list really would
be created at runtime.

% perl -Dts -le 'scalar($$, 42, 43)'

EXECUTING...

=>
(-e:0) enter
=>
(-e:0) nextstate
=>
(-e:1) pushmark
=> *

Here's the list (note the missing "42").

(-e:1) gvsv(main::$)
=> * IV(14592)
(-e:1) const(IV(43))
=> * IV(14592) IV(43)

Here's the op that evaluates the list in scalar context.

(-e:1) list

And here's the result.

=> IV(43)
(-e:1) leave

--
Steve

Ben Morrow

unread,
Nov 11, 2003, 11:45:50 PM11/11/03
to
Steve Grazzini <gr...@pobox.com> wrote:
> Ben Morrow <use...@morrow.me.uk> wrote:
> > Steve Grazzini <gr...@pobox.com> wrote:
> >> I suppose it would also be possible to say that the subroutine
> >> returns the *result* of evaluating a list in void context. And
> >> likewise, that this one returns the result of evaluating an array
> >> in scalar context:
> >>
> >> % perl -Ds -le 'sub f { @INC } scalar f()'
> >>
> >> But I'd rather say that this returns an array.
> >
> > But that would be quite wrong. In Perl, a function *cannot* return
> > an array, only a list if in list context or a scalar if in scalar.
>
> That's true, of course. I think I got it right earlier: f() returns
> the result of evaluating @INC in scalar context when it's called in
> scalar context, and the result of evaluating @INC in list context when
> it's called in list context. Condensing this to "f() returns @INC" is
> less precise, but maybe it's close enough to be useful, assuming that
> we all know you can't *really* return an array from a subroutine and
> do "push foo(), $elt" or whatever.

OK.

>
> > For instance, what about this
> >
> > % perl -le'sub f { caller } print scalar f'
> >
> > ? Would you say this returns 'the caller function', which is then
> > evaluated in scalar context?
>
> Well, no. That would be silly. :-)

Well.... I don't quite see as it's sillier than saying the sub above
returns @INC. This returns the result of evaluating caller() in list
context when in list context, and the result of evaluating caller() in
scalar context when in scalar context.

Both are simply a constructive use of sloppy language.

> > according to you, the result of 'evaluating a list in scalar context'
> > is its last element, which is not what is returned.
>
> That's because (as you must know) caller() doesn't return a list in
> scalar context. Since there's no list, this doesn't have anything
> to do with the behavior of a list in scalar context.

But my point was that neither was there a list in the @INC
case. '@INC' doesn't return a list in scalar context either: it
returns the number of elements it contains.

And, to get back to the original argument :), neither does map()
return a list in void context. It returns nothing.

<snip pods about lists and scalar ,>


> But the bit about the "scalar comma operator" seems to be misguided.
> If any of the earlier elements of those lists were variables, a list
> really would be created at runtime.
>
> % perl -Dts -le 'scalar($$, 42, 43)'
>
> EXECUTING...
>
> =>
> (-e:0) enter
> =>
> (-e:0) nextstate
> =>
> (-e:1) pushmark
> => *
>
> Here's the list (note the missing "42").
>
> (-e:1) gvsv(main::$)
> => * IV(14592)
> (-e:1) const(IV(43))
> => * IV(14592) IV(43)
>
> Here's the op that evaluates the list in scalar context.
>
> (-e:1) list
>
> And here's the result.
>
> => IV(43)
> (-e:1) leave

Interesting.....

So a better statement of all this is perhaps:

There is no 'scalar comma operator'. The comma operator builds a
list. A list evaluated in scalar context evaluates each of its members
in void context; except the last which is evaluated in scalar context
and returned. This may be optimized away at compile time (as usual).

Hmmm. This applies at complie time, not at run time. In

sub c {...}

my $x = (c, c);

the elements of the list are 'call sub c', rather than the results of
those calls; rather like returning 'the caller function' above :).
Very functional, and not at all suitable as a way of explaining it to
people :).

Ben

--
Although few may originate a policy, we are all able to judge it.
- Pericles of Athens, c.430 B.C.
b...@morrow.me.uk

0 new messages