after I posted my series of patches to perlipc.pod , I saw that tchrist posted
his version, which got accepted immediately. As a downside to that, I'll have
to restart my work. However, I noticed that perlipc.pod still has many
perceived issues. Here is a list of things I noticed:
* «defined($Config{sig_name}) || die "No sigs?"; »
Shouldn't it be using "or" instead of "||" or maybe an if?
*
<<<
foreach $name (split(" ", $Config{sig_name})) {
$signo{$name} = $i;
$signame[$i] = $name;
$i++;
}
>>>
"foreach my $name" (Gotta practice what we preach). Furthermore, someone said
we should recommend using a CPAN module for that instead.
* unless (kill(0 => $pid) || $!{EPERM}) {
warn "$pid looks dead";
}
unless and and ||? That's a bit confusing.
*
<<<
my $ALARM_EXCEPTION = "alarm clock restart";
eval {
local $SIG{ALRM} = sub { die $ALARM_EXCEPTION };
alarm 10;
flock(FH, 2) # blocking write lock
|| die "cannot flock: $!";
alarm 0;
};
if ($@ && $@ !~ quotemeta($ALARM_EXCEPTION)) { die }
>>>
Non-lexical filehandle.
*
<<<
# system return val is backwards, so && not ||
#
$ENV{PATH} .= ":/etc:/usr/etc";
if ( system("mknod", $path, "p")
&& system("mkfifo", $path) )
{
die "mk{nod,fifo} $path failed";
}
>>>
We probably want local $ENV{PATH} here, and can't we expect the mkfifo system
call to work globally already?
*
<<<
chdir(); # go home
my $FIFO = ".signature";
while (1) {
unless (-p $FIFO) {
unlink $FIFO; # discard any failure, will catch later
require POSIX; # delayed loading of heavy module
POSIX::mkfifo($FIFO, 0700)
|| die "can't mkfifo $FIFO: $!";
}
# next line blocks till there's a reader
open (FIFO, "> $FIFO") || die "can't open $FIFO: $!";
print FIFO "John Smith (smith\@host.org)\n", `fortune -s`;
close(FIFO) || die "can't close $FIFO: $!";
sleep 2; # to avoid dup signals
}
>>>
Bareword filehandle, and 2-args open and || instead of or. I won't mention
bareword filehandles again, but the exist in many other places.
*
<<<
use FileHandle;
use IPC::Open2;
$pid = open2(*Reader, *Writer, "cat -un");
print Writer "stuff\n";
$got = <Reader>;
>>>
We need to make it use strict friendly.
*
<<<
#!/usr/bin/perl -w
>>>
use warnings instead of "-w".
*
<<<
my ($remote, $port, $iaddr, $paddr, $proto, $line);
$remote = shift || "localhost";
$port = shift || 2345; # random port
if ($port =~ /\D/) { $port = getservbyname($port, "tcp") }
die "No port" unless $port;
$iaddr = inet_aton($remote) || die "no host: $remote";
>>>
we should declare the variables at first assignment instead of all in one
place.
*
Shouldn't the example use IO::Socket and friends?
*
<<<
And here's a multithreaded version. It's multithreaded in that
like most typical servers, it spawns (fork()s) a slave server to
handle the client request so that the master server can quickly
go back to service a new client.
>>>
The term "multithreaded" is misleading it. It is multi-processed - not
multithreaded, because it does not use threads.
*
<<<
Section 5 of CPAN's F<modules> file is devoted to "Networking, Device
Control (modems), and Interprocess Communication", and contains numerous
unbundled modules numerous networking modules, Chat and Expect operations,
CGI programming, DCE, FTP, IPC, NNTP, Proxy, Ptty, RPC, SNMP, SMTP, Telnet,
Threads, and ToolTalk--to name just a few.
>>>
We should no longer mention that modules file.
Should I send patches to correct all these issues (because the Perl
documentation should represent the best practices)? And I hope that this time
all my work will not be for naught again.
Regards,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
Rethinking CPAN - http://shlom.in/rethinking-cpan
<rindolf> She's a hot chick. But she smokes.
<go|dfish> She can smoke as long as she's smokin'.
Please reply to list if it's a mailing list post - http://shlom.in/reply .
Shlomi, why didnt you send this to tchrist, and cc p5p?
Dont expect Tom to see your posting.
He is the one you need to speak to about any of the issues that you
raise that are not outright bugs but rather style nits.
cheers,
Yves
--
perl -Mre=debug -e "/just|another|perl|hacker/"
Because he may or may not be too busy to notice. And it is simple
courtesy as you know he is the author, and has strong feelings about
his document.
That is *not* badly written code.
--tom
You would have a point if you there are code fragments that are generally
considered "badly written". But using '||' where you would prefer 'or',
or using FILE globs where you would use a lexical handle, doesn't make
"badly written" code. That's just a style preference. And naming anything
that isn't written according to your preferences "badly written" code
doesn't really get people to side with you.
Abigail
Having real issues is quite distinct from having perceived issues.
In the case of perlipc, all are from the latter set.
> Here is a list of things I noticed:
> * «defined($Config{sig_name}) || die "No sigs?"; »
> Shouldn't it be using "or" instead of "||" or maybe an if?
No, it should not. That conflicts with my own way of speaking
Perl, one which is self-consistent, perfectly safe, and followed
by a good number of core developers, such as Rafael Manfredi.
If you break my style, you break the document. And upon my
style, Damian has said:
And yes, they evince no lack of style.
Not my espoused style, but so many people forget that PBP was--at
its heart--a plea for code to be written in *any* consistent style,
consciously and rationally chosen to meet one's own needs. No-one,
I'm sure, would every accuse you of failing to do that.
If Damian does not condemn me, who are you to do so?
VETO
> *
> <<<
> foreach $name (split(" ", $Config{sig_name})) {
> $signo{$name} = $i;
> $signame[$i] = $name;
> $i++;
> }
> >>>
> "foreach my $name" (Gotta practice what we preach). Furthermore, someone said
> we should recommend using a CPAN module for that instead.
The tone and style of the Perl Documentation as set by Larry and myself is
to omit cluttering declarations from tiny snippets. They otherwise
distract from what the point of what is being illustrated. The exception
is if the point of the snippet is the declaration. Putting in declarations
for every two-bit line of code is madness. Look at perlfunc!
VETO
> * unless (kill(0 => $pid) || $!{EPERM}) {
> warn "$pid looks dead";
> }
> unless and and ||? That's a bit confusing.
I'm sorry you're confused. Me, I find DeMorgan's
Law confusing and therefore avoid its application
wherever possible.
unless I killed it or else I got a permission error
it looks dead
is perfectly clear.
Let's try it your way:
if (!kill(0 => $pid) && !$!{EPERM}) {
warn "$pid it looks dead";
}
See what a mess you've made?
Don't be ridiculous. Making people compute boolean
algebra in their heads through a surfeit of boolean
ops is a recipe for confusion.
VETO
> *
> <<<
> my $ALARM_EXCEPTION = "alarm clock restart";
> eval {
> local $SIG{ALRM} = sub { die $ALARM_EXCEPTION };
> alarm 10;
> flock(FH, 2) # blocking write lock
> || die "cannot flock: $!";
> alarm 0;
> };
> if ($@ && $@ !~ quotemeta($ALARM_EXCEPTION)) { die }
> >>>
> Non-lexical filehandle.
Touch noogies. This is a tiny example. $Did $you $really
$want $more $punctuation? @How %about $we *name $the &function,
$too, Like::
my $throw_up_and_alarm_exception_using_die = sub {
die $ALARM_EXCEPTION;
};
Or better yet, we can name our function:
THROW_UP_AND_ALARM_EXCEPTION_USING_DIE {
die $ALARM_EXCEPTION;
};
Except now you'll likely get yourself in a snit for it not having
enough #$%^W#$$^ marks.
VETO
> *
> <<<
> # system return val is backwards, so && not ||
> #
> $ENV{PATH} .= ":/etc:/usr/etc";
> if ( system("mknod", $path, "p")
> && system("mkfifo", $path) )
> {
> die "mk{nod,fifo} $path failed";
> }
> >>>
> We probably want local $ENV{PATH} here, and can't we expect the
> mkfifo system call to work globally already?
No, we most certainly cannot expect that! I didn't put that code in
there out of imagined problems. I put it in there because if I didn't,
it failed on some of systems I tested it on. Why? Because you cannot
count on the user to have those in his path, that's why.
VETO
As for the local(), I feel that again falls in the needless
category, although not so strongly as my other positions.
> *
> <<<
> chdir(); # go home
> my $FIFO = ".signature";
> while (1) {
> unless (-p $FIFO) {
> unlink $FIFO; # discard any failure, will catch later
> require POSIX; # delayed loading of heavy module
> POSIX::mkfifo($FIFO, 0700)
> || die "can't mkfifo $FIFO: $!";
> }
> # next line blocks till there's a reader
> open (FIFO, "> $FIFO") || die "can't open $FIFO: $!";
> print FIFO "John Smith (smith\@host.org)\n", `fortune -s`;
> close(FIFO) || die "can't close $FIFO: $!";
> sleep 2; # to avoid dup signals
> }
> >>>
> Bareword filehandle,
Cope. VETO.
> and 2-args open
THIS IS A MYTH!
There is nothing whatsoever wrong with using two-argument
open when you have complete control over the content of
those strings and you are not setting the encoding in the
open itself.
VETO.
> and || instead of or.
Broken style. VETO.
> I won't mention
> bareword filehandles again, but the exist in many other places.
VETO
> *
> <<<
> use FileHandle;
> use IPC::Open2;
> $pid = open2(*Reader, *Writer, "cat -un");
> print Writer "stuff\n";
> $got = <Reader>;
> >>>
> We need to make it use strict friendly.
No, we do not. Vide fricking supra.
> *
> <<<
> #!/usr/bin/perl -w
> >>>
> use warnings instead of "-w".
ACK
> *
> <<<
> my ($remote, $port, $iaddr, $paddr, $proto, $line);
> $remote = shift || "localhost";
> $port = shift || 2345; # random port
> if ($port =~ /\D/) { $port = getservbyname($port, "tcp") }
> die "No port" unless $port;
> $iaddr = inet_aton($remote) || die "no host: $remote";
> >>>
> we should declare the variables at first assignment instead of all in one
> place.
What? Three lines away is too far? I think not!
Anyway, that style is optimal for this construct:
my ( $remote, # asdfasdf
$port, # asdfasdf
$iaddr, # asdfasdf
$paddr, # asdfasdf
$proto, # asdfasdf
$line # asdfasdf
);
Are you saying my variable names are so obscure that it needs that
sort of commenting at the point of declaration?
> *
> Shouldn't the example use IO::Socket and friends?
No, do not Bowdlerize working code.
*HOWEVER*
A version or two of things using IO::Socket might reaonable go in there on
top of that--assuming you deem IO::Socket's documentation inadequate.
But to strike away how to do this in the only place it exists in the
documentation is inadvisable in the extreme, so much so that I'm sorely
tempted to use stronger language.
Fortunately, this time I shan't.
> And here's a multithreaded version. It's multithreaded in that
> like most typical servers, it spawns (fork()s) a slave server to
> handle the client request so that the master server can quickly
> go back to service a new client.
> >>>
> The term "multithreaded" is misleading it. It is multi-processed - not
> multithreaded, because it does not use threads.
It was how we talked about things when that code was written. I wrote
plenty of perl4 client-server code, and that's what it was. I believe
the Camel and the Cookbook have notes clarifying the original usage.
I can dig those out if need be.
> *
> <<<
> Section 5 of CPAN's F<modules> file is devoted to "Networking, Device
> Control (modems), and Interprocess Communication", and contains numerous
> unbundled modules numerous networking modules, Chat and Expect operations,
> CGI programming, DCE, FTP, IPC, NNTP, Proxy, Ptty, RPC, SNMP, SMTP, Telnet,
> Threads, and ToolTalk--to name just a few.
> >>>
> We should no longer mention that modules file.
ACK.
> Should I send patches to correct all these issues
I am not going to tell you want to do. But I will say
that I do not believe 97% of your "corrections" have
any merit whatsoever, and in fact suffer from demerits.
> (because the Perl
> documentation should represent the best practices)?
I again direct you to Damian's quote. Your statement
is simple, seductive, and misleading to the point of
being wrong.
> And I hope that this time all my work will not be for
> naught again.
Work on things that need working on, and it won't be.
Work on things that don't need working on, and it may.
Nobody can tell you what to do, but that is my opinion,
and I may be wrong.
--tom
1+. Sorry for saying "badly-written code". I didn't mean tchrist's code was
badly written just that the code that some Perl beginners show us is badly
written, non-idiomatic and/or non-modern, as it was inspired by out-of-date
books, tutorials, and other resourcs. I meant we should not demonstrate such
bad coding patterns that we feel are not desirable, by putting them inside the
core documentation.
> I'll comment on some specific items below.
>
> >> Shouldn't it be using "or" instead of "||" or maybe an if?
>
> I prefer "or" but I don't terribly care.
>
I can let it slide. Just noted it.
> >> foreach $name (split(" ", $Config{sig_name})) {
> >> $signo{$name} = $i;
> >> $signame[$i] = $name;
> >> $i++;
> >> }
> >
> > The tone and style of the Perl Documentation as set by Larry and myself
> > is
>
> That's an appeal to authority type argument, which I don't like. The
> tone and style were set when globals were more common. I think this
> is open for reasonable people to debate. Adding "my" costs nothing in
> obscuring the clarity of the point. Frankly, I think the whole thing
> could be written more idiomatically. Incrementing $i is just icky.
> E.g.:
>
> @signame = split(" ", $Config{sig_name});
> @signo{@signame} = (1) x @signame;
>
Actually, @signo should contain the signal number:
@signame = split(" ", $Config{sig_name});
%signo = map { $signame[$_] => $_ } (0 .. $#signame);
> >> * unless (kill(0 => $pid) || $!{EPERM}) {
> >> warn "$pid looks dead";
> >> }
> >>
> >> unless and and ||? That's a bit confusing.
> >
> > I'm sorry you're confused. Me, I find DeMorgan's
> > Law confusing and therefore avoid its application
> > wherever possible.
> >
> > unless I killed it or else I got a permission error
> > it looks dead
> >
> > is perfectly clear.
> >
> > Let's try it your way:
> >
> > if (!kill(0 => $pid) && !$!{EPERM}) {
> > warn "$pid it looks dead";
> > }
> >
> > See what a mess you've made?
>
> I'm torn. The semantics of a "successful" kill 0 meaning "alive" and
> the use of "$!" vs "! $!" make this ugly both ways. We're into
> double/triple negative territory.
:-).
>
> >> my $ALARM_EXCEPTION = "alarm clock restart";
> >> eval {
> >> local $SIG{ALRM} = sub { die $ALARM_EXCEPTION };
> >> alarm 10;
> >> flock(FH, 2) # blocking write lock
> >> || die "cannot flock: $!";
> >> alarm 0;
> >> };
> >> if ($@ && $@ !~ quotemeta($ALARM_EXCEPTION)) { die }
> >>
> >>
> >> Non-lexical filehandle.
> >
> > Touch noogies.
>
> I'd rather not touch anyone's noogies, thanks.
>
> I think it reads fine either as "FH" or "$handle". If there is a
> general principle of "avoid non-lexical filehandles" then it's worth
> changing. Short of a consensus (or pumpking) decision, I think it can
> be left alone. It's not *opening* FH, it's just an example of flock()
>
OK.
> >> # system return val is backwards, so && not ||
> >> #
> >> $ENV{PATH} .= ":/etc:/usr/etc";
> >> if ( system("mknod", $path, "p")
> >> && system("mkfifo", $path) )
> >> {
> >> die "mk{nod,fifo} $path failed";
> >> }
> >>
> >>
> >> We probably want local $ENV{PATH} here, and can't we expect the
> >> mkfifo system call to work globally already?
> >
> > No, we most certainly cannot expect that! I didn't put that code in
> > there out of imagined problems. I put it in there because if I didn't,
> > it failed on some of systems I tested it on. Why? Because you cannot
> > count on the user to have those in his path, that's why.
>
> I agree that $ENV{PATH} doesn't need to be localized for this example.
> This is an example of "find it elsewhere" and messing with $ENV{PATH}
> is just a reminder of that. Is it important for this tutorial to hint
> at where it might be? I don't know.
>
> Is it likely for "mknod" or "mkfifo" to fail if they are indeed
> present in the path? If not, the point might be clearer with IPC::Cmd
> and can_run:
>
> use IPC::Cmd;
> for ( ["mknod", $path, "p"], ["mkfifo", $path] ) {
> if (can_run($_->[0])) {
> system(@$_) and die "Command failed: @$_";
> }
> }
>
> Otherwise, the original example as is is not distinguishing between
> failure (1) and can't run (-1), though I don't really know if that is
> important for the purpose of the example.
I don't think it is.
>
> >> chdir(); # go home
> >> my $FIFO = ".signature";
> >>
> >> while (1) {
> >> unless (-p $FIFO) {
> >> unlink $FIFO; # discard any failure, will catch later
> >> require POSIX; # delayed loading of heavy module
> >> POSIX::mkfifo($FIFO, 0700)
> >> || die "can't mkfifo $FIFO: $!";
> >> }
> >>
> >> # next line blocks till there's a reader
> >> open (FIFO, "> $FIFO") || die "can't open $FIFO: $!";
> >> print FIFO "John Smith (smith\@host.org)\n", `fortune -s`;
> >> close(FIFO) || die "can't close $FIFO: $!";
> >> sleep 2; # to avoid dup signals
> >> }
> >>
> >> Bareword filehandle,
> >
> > Cope. VETO.
> >
> >> and 2-args open
> >
> > THIS IS A MYTH!
> >
> > There is nothing whatsoever wrong with using two-argument
> > open when you have complete control over the content of
> > those strings and you are not setting the encoding in the
> > open itself.
>
> Same argument on my part as before about principles, but stronger. If
> we're actually showing an "open" call, I'd much prefer to have
> three-arg open to a lexical handle. Yes, a two-arg call is safe in
> this circumstance. But no clarity is lost with a three-arg open,
> either. Newbies crib documentation and/or adopt the styles they see
> there. I'd rather they see the "always safe" version instead of the
> "safe this time" version. Certainly, I understand that Tom disagrees,
> which is why I'd like an agreed set of guidelines so it isn't just
> individual style debate yet again.
>
+1.
> >> use warnings instead of "-w".
> >
> > ACK
>
> +1
>
> >> my ($remote, $port, $iaddr, $paddr, $proto, $line);
> >>
> >> $remote = shift || "localhost";
> >> $port = shift || 2345; # random port
> >> if ($port =~ /\D/) { $port = getservbyname($port, "tcp") }
> >> die "No port" unless $port;
> >> $iaddr = inet_aton($remote) || die "no host: $remote";
> >>
> >> we should declare the variables at first assignment instead of all in
> >> one place.
> >
> > What? Three lines away is too far? I think not!
>
> I think it's fine on one line. The 'extra' line vs inline 'my' is
> trivial in an example of that length.
>
OK.
> >> Shouldn't the example use IO::Socket and friends?
> >
> > No, do not Bowdlerize working code.
>
> Unless there is good reason why one should use IO::Socket, I don't see
> a reason to switch. If IO::Socket made the example simpler, then it
> might be worth considering.
>
Well, we no longer recommend people to use the lower-level modules instead of
IO::Socket , so it may again be a bad example and I've already started
converting the code to IO::Socket in my branch.
> >> And here's a multithreaded version. It's multithreaded in that
> >> like most typical servers, it spawns (fork()s) a slave server to
> >> handle the client request so that the master server can quickly
> >> go back to service a new client.
> >>
> >>
> >> The term "multithreaded" is misleading it. It is multi-processed - not
> >> multithreaded, because it does not use threads.
> >
> > It was how we talked about things when that code was written. I wrote
> > plenty of perl4 client-server code, and that's what it was. I believe
> > the Camel and the Cookbook have notes clarifying the original usage.
> > I can dig those out if need be.
>
> I think it can be modernized with no loss of clarity and with less
> potential for confusion to someone who reads it literally.
>
+1.
> >> We should no longer mention that modules file.
> >
> > ACK.
>
> +1
>
+1.
> >> Should I send patches to correct all these issues
>
> Shlomi, I would encourage you to do things in small chunks, carefully
> rebased off the trunk. The email you wrote to start this thread was
> the right level of granularity. Some of your past edits were so
> sweeping that it was hard to comprehend the impact. You were also
> regularly merging trunk into your branch, which made actually
> following your commit series very difficult, and thus hard to comment
> on or apply.
OK, I'll try to wrap my head around git rebase.
Regards and thanks,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
"The Human Hacking Field Guide" - http://shlom.in/hhfg
Let's get a few things straight.
First, we are talking here about Perl documentation. It's main purpose is
to explain Perl, every nook and cranny. It's not intended as a learning
Perl book. It's a reference guide. Yes, you can learn Perl that way (I
did), but that's not its main purpose. The documenation takes one thing
at a time, discusses it, and, ideally, has a short example showing the
discussed construct, and as little as anything else.
Second, "badly written", and "non idiomatic" are very subjective terms.
Unless you can clearly indicate *why* something is badly written or
"non idiomatic", I rather don't see such labels used. That counts for
the labels "bad coding pattern" and "not desirabe" as well. Larry has
said repeatedly "it's ok to talk baby-Perl".
Third, the term "modern Perl" makes me twitch in a bad way. I don't
understand what it is, or why 2010 is the year to jump on this
bandwagon. (I wonder which piper to follow in 2011).
Fourth, if documentation is out of date, it's not just the code examples
that need to be updated - whatever it is the example show needs to be
updated. (Otherwise, it wouldn't be outdated). But note that unless the
feature has actually been removed from Perl, its documentation should not
disappear.
> > >> foreach $name (split(" ", $Config{sig_name})) {
> > >> $signo{$name} = $i;
> > >> $signame[$i] = $name;
> > >> $i++;
> > >> }
> > >
> > > The tone and style of the Perl Documentation as set by Larry and myself
> > > is
> >
> > That's an appeal to authority type argument, which I don't like. The
> > tone and style were set when globals were more common. I think this
> > is open for reasonable people to debate. Adding "my" costs nothing in
> > obscuring the clarity of the point. Frankly, I think the whole thing
> > could be written more idiomatically. Incrementing $i is just icky.
> > E.g.:
> >
> > @signame = split(" ", $Config{sig_name});
> > @signo{@signame} = (1) x @signame;
> >
>
> Actually, @signo should contain the signal number:
>
> @signame = split(" ", $Config{sig_name});
> %signo = map { $signame[$_] => $_ } (0 .. $#signame);
If we really want to aim at newbies, do we really want to change a simple
loop into a something tricky that tripped up one experienced Perl person,
and needs to be written with a map and the $# sigil?
I prefer the original. In normal code, I would write 'my $name', but there's
only a limited with to play with if you want to resulting manual page to
show in an 80 character term; I don't mind the 'my' not being there. The
example isn't about foreach syntax.
> > >> # system return val is backwards, so && not ||
> > >> #
> > >> $ENV{PATH} .= ":/etc:/usr/etc";
> > >> if ( system("mknod", $path, "p")
> > >> && system("mkfifo", $path) )
> > >> {
> > >> die "mk{nod,fifo} $path failed";
> > >> }
> > >>
> > >>
> > >> We probably want local $ENV{PATH} here, and can't we expect the
> > >> mkfifo system call to work globally already?
> > >
> > > No, we most certainly cannot expect that! I didn't put that code in
> > > there out of imagined problems. I put it in there because if I didn't,
> > > it failed on some of systems I tested it on. Why? Because you cannot
> > > count on the user to have those in his path, that's why.
> >
> > I agree that $ENV{PATH} doesn't need to be localized for this example.
> > This is an example of "find it elsewhere" and messing with $ENV{PATH}
> > is just a reminder of that. Is it important for this tutorial to hint
> > at where it might be? I don't know.
How many systems are there were 1) mknod and mkfifo are in either /etc/
or /usr/etc/, and 2) the directory they're in aren't in the standard root
PATH? Maybe it's better to take out the $ENV{PATH} line out, and replace
it with something like:
# Make sure 'mknod' and 'mkfifo' are in your PATH.
which explains the $ENV{PATH} line without tying itself to a particular OS.
> >
> > Is it likely for "mknod" or "mkfifo" to fail if they are indeed
> > present in the path? If not, the point might be clearer with IPC::Cmd
> > and can_run:
> >
> > use IPC::Cmd;
> > for ( ["mknod", $path, "p"], ["mkfifo", $path] ) {
> > if (can_run($_->[0])) {
> > system(@$_) and die "Command failed: @$_";
> > }
> > }
I don't find this clearer at all. It requires knowledge of IPC::Cmd, and
untwisting the C<< for ( ["mknod", $path, "p"], ["mkfifo", $path] ) >> line.
Now, one may not understand the original right away, but at least the syntax
doesn't bog one down in understanding - which, IMO, the above does.
[ Another example with bare filehandles ]
> > Same argument on my part as before about principles, but stronger. If
> > we're actually showing an "open" call, I'd much prefer to have
> > three-arg open to a lexical handle. Yes, a two-arg call is safe in
> > this circumstance. But no clarity is lost with a three-arg open,
> > either. Newbies crib documentation and/or adopt the styles they see
> > there. I'd rather they see the "always safe" version instead of the
> > "safe this time" version. Certainly, I understand that Tom disagrees,
> > which is why I'd like an agreed set of guidelines so it isn't just
> > individual style debate yet again.
> >
>
> +1.
I agree with Tom.
Also, newbies *will* encounter bare filehandles once they come out of
kindergarten. No need to shield newbies from them in the core documentation.
> > >> use warnings instead of "-w".
> > >
> > > ACK
> >
> > +1
> >
> > >> my ($remote, $port, $iaddr, $paddr, $proto, $line);
> > >>
> > >> $remote = shift || "localhost";
> > >> $port = shift || 2345; # random port
> > >> if ($port =~ /\D/) { $port = getservbyname($port, "tcp") }
> > >> die "No port" unless $port;
> > >> $iaddr = inet_aton($remote) || die "no host: $remote";
> > >>
> > >> we should declare the variables at first assignment instead of all in
> > >> one place.
> > >
> > > What? Three lines away is too far? I think not!
> >
> > I think it's fine on one line. The 'extra' line vs inline 'my' is
> > trivial in an example of that length.
> >
The only problem I have with this example is that the
'|| die "no host: $remote";' wraps into the 81 column after formatting.
A C<< s/ = /= /g >> would solve this, while keeping the vertical
lining up of the operators (some || don't line up, which is someone
disturbing, but not something I'd change for the sake of changing).
>
> OK.
>
> > >> Shouldn't the example use IO::Socket and friends?
> > >
> > > No, do not Bowdlerize working code.
> >
> > Unless there is good reason why one should use IO::Socket, I don't see
> > a reason to switch. If IO::Socket made the example simpler, then it
> > might be worth considering.
> >
>
> Well, we no longer recommend people to use the lower-level modules instead of
> IO::Socket , so it may again be a bad example and I've already started
> converting the code to IO::Socket in my branch.
Instead of changing code to use IO::Socket, why not *add* an example that
uses it? Or add such an example in IO::Socket, with perlipc having a pointer
to it?
Abigail
> if ($@&& $@ !~ quotemeta($ALARM_EXCEPTION)) { die }
>>>>
>
> Non-lexical filehandle.
>
IMO, direct testing of $@ should also be discouraged.
It should test the (enforced) truth of the return value of the eval.
> *
>
> <<<
> # system return val is backwards, so&& not ||
I agree to most, if not all of your 'corrrections'.
--
Ruud
We do, honestly. I'm tired of having to explain to newbies why the
official perl documentation is not strict friendly, when I tell them
they should use strict. **I don't know how to explain that to them**,
it simply doesn't compute.
Leon
>> We do, honestly. I'm tired of having to explain to newbies why the
>> official perl documentation is not strict friendly, when I tell them
>> they should use strict. **I don't know how to explain that to them**,
>> it simply doesn't compute.
>You've had the "But I copied and pasted it directly from the documentation,
>and now my program doesn't work anymore!" discussion too?
If they are using strict, it will immediately show itself.
If they are not, there is absolutely no hope for them.
--tom
>We do, honestly. I'm tired of having to explain to newbies why the
>official perl documentation is not strict friendly, when I tell them
>they should use strict. **I don't know how to explain that to them**,
>it simply doesn't compute.
Then they just aren't smart enough to handle programming, I guess.
I have never ever had the least problem. I've taught many thousands
of students, directly.
I don't believe you.
--tom
[...]
I don't much like "me too" posts that just dilute the signal for
noise. So I'm bad, because I again find nothing at all to disagree
with in what Abigail has written here.
I'll try to add something anyway.
> Third, the term "modern Perl" makes me twitch in a bad way. I don't
> understand what it is, or why 2010 is the year to jump on this
> bandwagon. (I wonder which piper to follow in 2011).
I have your same twitchiness. It's become almost a "negative
flash word" for me. It reminds me too much of a propaganda
campaign, some marketing hoodwinking, a rebranding by the a
political correctness gone mad.
> But note that unless the feature has actually been removed from
> Perl, its documentation should not disappear.
That's what I mean by bowlderized. There's been stuff taken out
for no good reason, stuff that works just fine. It's the
brainwashing police making sure you think no thoughts they
don't approve of.
>>>> The tone and style of the Perl Documentation as set by Larry and myself
>>>> is
>>>
>>> That's an appeal to authority type argument, which I don't like.
Absolutely. It's recognizing that it was once a garment largely
of one cloth woven, not the ragged patchwork thing it has become.
I actually don't think it's fixable. What the devil is a "wide hex
char" for goodness' sake!? The thing is full of crud like that.
>>> The
>>> tone and style were set when globals were more common.
Oh no, that's not true at all. Most of it was written long after we had
lexically scoped variables, and if you can find something there before we
had dynamically scoped variabled, you have a very good iea.
>>> I think this is open for reasonable people to debate. Adding
>>> "my" costs nothing in obscuring the clarity of the point.
WRONG!!!
<88> WRONG!!!
while (<>) {
chomp;
next unless -f $_; # ignore specials
#...
}
<95> WRONG!!!
print "Can do.\n" if -r $a || -w _ || -x _;
<96> WRONG!!!
stat($filename);
print "Readable\n" if -r _;
print "Writable\n" if -w _;
print "Executable\n" if -x _;
print "Setuid\n" if -u _;
print "Setgid\n" if -g _;
print "Sticky\n" if -k _;
print "Text\n" if -T _;
print "Binary\n" if -B _;
<111> WRONG!!!
eval {
local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
alarm $timeout;
$nread = sysread SOCKET, $buffer, $size;
alarm 0;
};
if ($@) {
die unless $@ eq "alarm\n"; # propagate unexpected errors
# timed out
}
else {
# didn't
}
<116>
sub tan { sin($_[0]) / cos($_[0]) }
<146> WRONG!!!
# 0 1 2
($package, $filename, $line) = caller;
<148> WRONG!!!
# 0 1 2 3 4
($package, $filename, $line, $subroutine, $hasargs,
<149> WRONG!!! WRONG!!! WRONG!!!
# 5 6 7 8 9 10
$wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
= caller($i);
<163> WRONG!!!
$cnt = chmod 0755, "foo", "bar";
chmod 0755, @executables;
$mode = "0644"; chmod $mode, "foo"; # !!! sets mode to
# --w----r-T
$mode = "0644"; chmod oct($mode), "foo"; # this is better
$mode = 0644; chmod $mode, "foo"; # this is best
<165>
open(my $fh, "<", "foo");
my $perm = (stat $fh)[2] & 07777;
chmod($perm | 0600, $fh);
<167> WRONG!!!
use Fcntl qw( :mode );
chmod S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, @executables;
# Identical to the chmod 0755 of the example above.
<172> WRONG!!! WRONG!!!
while (<>) {
chomp; # avoid \n on last field
@array = split(/:/);
# ...
}
<175> WRONG!!! WRONG!!!
chomp($cwd = `pwd`);
chomp($answer = <STDIN>);
<188> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$cnt = chown $uid, $gid, 'foo', 'bar';
chown $uid, $gid, @filenames;
<191> WRONG!!!
print "User: ";
chomp($user = <STDIN>);
print "Files: ";
chomp($pattern = <STDIN>);
<192> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
($login,$pass,$uid,$gid) = getpwnam($user)
or die "$user not in passwd file";
<193> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
@ary = glob($pattern); # expand filenames
chown $uid, $gid, @ary;
<195> WRONG!!!
use POSIX qw(sysconf _PC_CHOWN_RESTRICTED);
$can_chown_giveaway = not sysconf(_PC_CHOWN_RESTRICTED);
<214>
open(OUTPUT, '|sort >foo') # pipe to sort
or die "Can't start sort: $!";
#... # print stuff to output
close OUTPUT # wait for sort to finish
or warn $! ? "Error closing sort pipe: $!"
: "Exit status $? from sort";
open(INPUT, 'foo') # get sort's results
or die "Can't open 'foo' for input: $!";
<224>
while (EXPR) {
### redo always comes here
do_something;
} continue {
### next always comes here
do_something_else;
# then back the top to re-check EXPR
}
### last always comes here
<231>
sub acos { atan2( sqrt(1 - $_[0] * $_[0]), $_[0] ) }
<240> WRONG!!!
$pwd = (getpwuid($<))[1];
<241> WRONG!!!
system "stty -echo";
print "Password: ";
chomp($word = <STDIN>);
print "\n";
system "stty echo";
<242> WRONG!!!
if (crypt($word, $pwd) ne $pwd) {
die "Sorry...\n";
} else {
print "ok\n";
}
<254> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
# print out history file offsets
dbmopen(%HIST,'/usr/lib/news/history',0666);
while (($key,$val) = each %HIST) {
print $key, ' = ', unpack('L',$val), "\n";
}
dbmclose(%HIST);
<257> WRONG!!!
use DB_File;
dbmopen(%NS_Hist, "$ENV{HOME}/.netscape/history.db")
or die "Can't open netscape history file: $!";
<264> WRONG!!! WRONG!!!
if (@an_array) { print "has array elements\n" }
if (%a_hash) { print "has hash members\n" }
<267> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
print if defined $switch{'D'};
print "$val\n" while defined($val = pop(@ary));
die "Can't readlink $sym: $!"
unless defined($value = readlink $sym);
sub foo { defined &$bar ? &$bar(@_) : die "No bar"; }
$debugging = 0 unless defined $debugging;
<269>
"ab" =~ /a(.*)b/;
<279> WRONG!!!
%hash = (foo => 11, bar => 22, baz => 33);
$scalar = delete $hash{foo}; # $scalar is 11
$scalar = delete @hash{qw(foo bar)}; # $scalar is 22
@array = delete @hash{qw(foo bar baz)}; # @array is (undef,undef,33)
<281> WRONG!!! WRONG!!!
foreach $key (keys %HASH) {
delete $HASH{$key};
}
<282> WRONG!!! WRONG!!!
foreach $index (0 .. $#ARRAY) {
delete $ARRAY[$index];
}
<284> WRONG!!!
delete @HASH{keys %HASH};
<285> WRONG!!!
delete @ARRAY[0 .. $#ARRAY];
<287> WRONG!!!
%HASH = (); # completely empty %HASH
undef %HASH; # forget %HASH ever existed
<288> WRONG!!!
@ARRAY = (); # completely empty @ARRAY
undef @ARRAY; # forget @ARRAY ever existed
<290> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
delete $ref->[$x][$y]{$key};
delete @{$ref->[$x][$y]}{$key1, $key2, @morekeys};
<291> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
delete $ref->[$x][$y][$index];
delete @{$ref->[$x][$y]}[$index1, $index2, @moreindices];
<295>
die "Can't cd to spool: $!\n" unless chdir '/usr/spool/news';
chdir '/usr/spool/news' or die "Can't cd to spool: $!\n"
<298>
die "/etc/games is no good";
die "/etc/games is no good, stopped";
<300>
/etc/games is no good at canasta line 123.
/etc/games is no good, stopped at canasta line 123.
<302>
eval { ... };
die unless $@ =~ /Expected exception/;
<306>
exit $! if $!; # errno
exit $? >> 8 if $? >> 8; # child exit status
exit 255; # last resort
<309>
use Scalar::Util "blessed";
<310>
eval { ... ; die Some::Module::Exception->new( FOO => "bar" ) };
if (my $ev_err = $@) {
if (blessed($ev_err) && $ev_err->isa("Some::Module::Exception")) {
# handle Some::Module::Exception
}
else {
# handle all other possible exceptions
}
}
<313> WRONG!!!
die @_ if $^S;
<323>
do 'stat.pl';
<325>
eval `cat stat.pl`;
<330> WRONG!!!
# read in config files: system first, then user
for $file ("/share/prog/defaults.rc",
"$ENV{HOME}/.someprogrc")
{
unless ($return = do $file) {
warn "couldn't parse $file: $@" if $@;
warn "couldn't do $file: $!" unless defined $return;
warn "couldn't run $file" unless $return;
}
}
<341> WRONG!!! WRONG!!! WRONG!!!
while (($key, $value) = each %hash) {
print $key, "\n";
delete $hash{$key}; # This is safe
}
<343> WRONG!!! WRONG!!!
while (($key,$value) = each %ENV) {
print "$key=$value\n";
}
<345> WRONG!!! WRONG!!! WRONG!!!
while (($key,$value) = each $hashref) { ... }
<354> WRONG!!!
# reset line numbering on each input file
while (<>) {
next if /^\s*#/; # skip comments
print "$.\t$_";
} continue {
close ARGV if eof; # Not eof()!
}
<355> WRONG!!!
# insert dashes just before last line of last file
while (<>) {
if (eof()) { # check for end of last file
print "--------------\n";
}
print;
last if eof(); # needed if we're reading from a terminal
}
<368> WRONG!!! WRONG!!!
# make divide-by-zero nonfatal
eval { $answer = $a / $b; }; warn $@ if $@;
<369> WRONG!!! WRONG!!!
# same thing, but less efficient
eval '$answer = $a / $b'; warn $@ if $@;
<370> WRONG!!!
# a compile-time error
eval { $answer = }; # WRONG
<371> WRONG!!!
# a run-time error
eval '$answer ='; # sets $@
<373> WRONG!!! WRONG!!!
# a private exception trap for divide-by-zero
eval { local $SIG{'__DIE__'}; $answer = $a / $b; };
warn $@ if $@;
<375>
# __DIE__ hooks may modify error messages
{
local $SIG{'__DIE__'} =
sub { (my $x = $_[0]) =~ s/foo/bar/g; die $x };
eval { die "foo lives here" };
print $@ if $@; # prints "bar lives here"
}
<378> WRONG!!! WRONG!!!
eval $x; # CASE 1
eval "$x"; # CASE 2
<379> WRONG!!! WRONG!!!
eval '$x'; # CASE 3
eval { $x }; # CASE 4
<380> WRONG!!! WRONG!!!
eval "\$$x++"; # CASE 5
$$x++; # CASE 6
<383>
# alter $@ on nefarious repugnancy only
{
my $e;
{
local $@; # protect existing $@
eval { test_repugnancy() };
# $@ =~ /nefarious/ and die $@; # DOES NOT WORK
$@ =~ /nefarious/ and $e = $@;
}
die $e if defined $e
}
<390>
exec ('foo') or print STDERR "couldn't exec foo: $!";
{ exec ('foo') }; print STDERR "couldn't exec foo: $!";
<392>
exec '/bin/echo', 'Your arguments are: ', @ARGV;
exec "sort $outfile | uniq";
<394>
$shell = '/bin/csh';
exec $shell '-sh'; # pretend it's a login shell
<396>
exec {'/bin/csh'} '-sh'; # pretend it's a login shell
<399> WRONG!!!
@args = ( "echo surprise" );
<400> WRONG!!! WRONG!!!
exec @args; # subject to shell escapes
# if @args == 1
exec { $args[0] } @args; # safe even with one-arg list
<406> WRONG!!! WRONG!!!
print "Exists\n" if exists $hash{$key};
print "Defined\n" if defined $hash{$key};
print "True\n" if $hash{$key};
<408> WRONG!!! WRONG!!!
print "Exists\n" if exists $array[$index];
print "Defined\n" if defined $array[$index];
print "True\n" if $array[$index];
<411>
print "Exists\n" if exists &subroutine;
print "Defined\n" if defined &subroutine;
<413> WRONG!!! WRONG!!! WRONG!!!
if (exists $ref->{A}->{B}->{$key}) { }
if (exists $hash{A}{B}{$key}) { }
<414> WRONG!!! WRONG!!! WRONG!!!
if (exists $ref->{A}->{B}->[$ix]) { }
if (exists $hash{A}{B}[$ix]) { }
<415> WRONG!!! WRONG!!!
if (exists &{$ref->{A}{B}{$key}}) { }
<417> WRONG!!!
undef $ref;
if (exists $ref->{"Some key"}) { }
print $ref; # prints HASH(0x80d3d5c)
<420>
exists ⊂ # OK
exists &sub(); # Error
<424> WRONG!!!
$ans = <STDIN>;
exit 0 if $ans =~ /^[Xx]/;
<433>
use Fcntl;
<435> WRONG!!! WRONG!!!
use Fcntl;
fcntl($filehandle, F_GETFL, $packed_return_buffer)
or die "can't fcntl F_GETFL: $!";
<439>
use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
<440> WRONG!!!
$flags = fcntl(REMOTE, F_GETFL, 0)
or die "Can't get flags for the socket: $!\n";
<441> WRONG!!!
$flags = fcntl(REMOTE, F_SETFL, $flags | O_NONBLOCK)
or die "Can't set flags for the socket: $!\n";
<445> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
if (fileno(THIS) == fileno(THAT)) {
print "THIS and THAT are dups\n";
}
<456>
use Fcntl qw(:flock SEEK_END); # import LOCK_* and SEEK_END constants
<457>
sub lock {
my ($fh) = @_;
flock($fh, LOCK_EX) or die "Cannot lock mailbox - $!\n";
<458> WRONG!!!
# and, in case someone appended while we were waiting...
seek($fh, 0, SEEK_END) or die "Cannot seek - $!\n";
}
<459>
sub unlock {
my ($fh) = @_;
flock($fh, LOCK_UN) or die "Cannot unlock mailbox - $!\n";
}
<460>
open(my $mbox, ">>", "/usr/spool/mail/$ENV{'USER'}")
or die "Can't open mailbox: $!";
<461> WRONG!!! WRONG!!!
lock($mbox);
print $mbox $msg,"\n\n";
unlock($mbox);
<471> WRONG!!! WRONG!!!
format Something =
Test: @<<<<<<<< @||||| @>>>>>
$str, $%, '$' . int($num)
.
<472> WRONG!!! WRONG!!! WRONG!!!
$str = "widget";
$num = $cost/$quantity;
$~ = 'Something';
write;
<480> WRONG!!!
if ($BSD_STYLE) {
system "stty cbreak </dev/tty >/dev/tty 2>&1";
}
else {
system "stty", '-icanon', 'eol', "\001";
}
<481> WRONG!!!
$key = getc(STDIN);
<482> WRONG!!!
if ($BSD_STYLE) {
system "stty -cbreak </dev/tty >/dev/tty 2>&1";
}
else {
system 'stty', 'icanon', 'eol', '^@'; # ASCII NUL
}
print "\n";
<487> WRONG!!!
$login = getlogin || getpwuid($<) || "Kilroy";
<491> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
use Socket;
$hersockaddr = getpeername(SOCK);
($port, $iaddr) = sockaddr_in($hersockaddr);
$herhostname = gethostbyaddr($iaddr, AF_INET);
$herstraddr = inet_ntoa($iaddr);
<530> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
($name,$passwd,$uid,$gid,
$quota,$comment,$gcos,$dir,$shell,$expire) = getpw*
($name,$passwd,$gid,$members) = getgr*
($name,$aliases,$addrtype,$length,@addrs) = gethost*
($name,$aliases,$addrtype,$net) = getnet*
($name,$aliases,$proto) = getproto*
($name,$aliases,$port,$proto) = getserv*
<534> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$uid = getpwnam($name);
$name = getpwuid($num);
$name = getpwent();
$gid = getgrnam($name);
$name = getgrgid($num);
$name = getgrent();
#etc.
<538> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
($a,$b,$c,$d) = unpack('W4',$addr[0]);
<540> WRONG!!! WRONG!!!
use Socket;
$iaddr = inet_aton("127.1"); # or whatever address
$name = gethostbyaddr($iaddr, AF_INET);
<541> WRONG!!! WRONG!!!
# or going the other way
$straddr = inet_ntoa($iaddr);
<543> WRONG!!! WRONG!!!
use Socket;
$packed_ip = gethostbyname("www.perl.org");
if (defined $packed_ip) {
$ip_address = inet_ntoa($packed_ip);
}
<546> WRONG!!! WRONG!!! WRONG!!!
use File::stat;
use User::pwent;
$is_his = (stat($filename)->uid == pwent($whoever)->uid);
<550> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
use Socket;
$mysockaddr = getsockname(SOCK);
($port, $myaddr) = sockaddr_in($mysockaddr);
printf "Connect to %s [%s]\n",
scalar gethostbyaddr($myaddr, AF_INET),
inet_ntoa($myaddr);
<555>
use Socket qw(:all);
<556>
defined(my $tcp = getprotobyname("tcp"))
or die "Could not determine the protocol number for tcp";
# my $tcp = IPPROTO_TCP; # Alternative
my $packed = getsockopt($socket, $tcp, TCP_NODELAY)
or die "getsockopt TCP_NODELAY: $!";
my $nodelay = unpack("I", $packed);
print "Nagle's algorithm is turned ", $nodelay ? "off\n" : "on\n";
<562> WRONG!!!
@many = glob "{apple,tomato,cherry}={green,yellow,red}";
<574> WRONG!!!
goto ("FOO", "BAR", "GLARCH")[$i];
<582> WRONG!!! WRONG!!!
@foo = grep(!/^#/, @bar); # weed out comments
<584> WRONG!!! WRONG!!!
@foo = grep {!/^#/} @bar; # weed out comments
<591>
print hex '0xAf'; # prints '175'
print hex 'aF'; # same
<603>
require "sys/ioctl.ph"; # probably in $Config{archlib}/sys/ioctl.ph
<606>
if OS returns: then Perl returns:
-1 undefined value
0 string "0 but true"
anything else that number
<608> WRONG!!!
$retval = ioctl(...) || -1;
printf "System returned %d\n", $retval;
<612> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$rec = join(':', $login,$passwd,$uid,$gid,$gcos,$home,$shell);
<620> WRONG!!! WRONG!!!
@keys = keys %ENV;
@values = values %ENV;
while (@keys) {
print pop(@keys), '=', pop(@values), "\n";
}
<622> WRONG!!! WRONG!!!
foreach $key (sort(keys %ENV)) {
print $key, '=', $ENV{$key}, "\n";
}
<625> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
foreach $key (sort { $hash{$b} <=> $hash{$a} } keys %hash) {
printf "%4d %s\n", $hash{$key}, $key;
}
<627> WRONG!!!
keys %hash = 200;
<630> WRONG!!! WRONG!!!
for (keys $hashref) { ... }
for (keys $obj->get_arrayref) { ... }
<635> WRONG!!! WRONG!!! WRONG!!!
$cnt = kill 1, $child1, $child2;
kill 9, @goners;
<643> WRONG!!!
LINE: while (<STDIN>) {
last LINE if /^$/; # exit when done with header
#...
}
<695> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
# 0 1 2 3 4 5 6 7 8
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime(time);
<698> WRONG!!! WRONG!!! WRONG!!!
my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
print "$abbr[$mon] $mday";
# $mon=9, $mday=18 gives "Oct 18"
<700> WRONG!!!
$year += 1900;
<703> WRONG!!! WRONG!!!
$year = sprintf("%02d", $year % 100);
<708> WRONG!!!
$now_string = localtime; # e.g., "Thu Oct 13 04:54:34 1994"
<711> WRONG!!!
use POSIX qw(strftime);
$now_string = strftime "%a %b %e %H:%M:%S %Y", localtime;
# or for GMT formatted appropriately for your locale:
$now_string = strftime "%a %b %e %H:%M:%S %Y", gmtime;
<722>
sub log10 {
my $n = shift;
return log($n)/log(10);
}
<733> WRONG!!! WRONG!!!
@chars = map(chr, @nums);
<735> WRONG!!! WRONG!!!
%hash = map { get_a_key_for($_) => $_ } @array;
<737> WRONG!!! WRONG!!! WRONG!!!
%hash = ();
foreach (@array) {
$hash{get_a_key_for($_)} = $_;
}
<741> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
%hash = map { "\L$_" => 1 } @array # perl guesses EXPR. wrong
%hash = map { +"\L$_" => 1 } @array # perl guesses BLOCK. right
%hash = map { ("\L$_" => 1) } @array # this also works
%hash = map { lc($_) => 1 } @array # as does this.
%hash = map +( lc($_) => 1 ), @array # this is EXPR and works!
<742> WRONG!!!
%hash = map ( lc($_), 1 ), @array # evaluates to (1, @array)
<744> WRONG!!!
@hashes = map +{ lc($_) => 1 }, @array # EXPR, so needs comma at end
<755>
use IPC::SysV;
<772> WRONG!!!
LINE: while (<STDIN>) {
next LINE if /^#/; # discard comments
#...
}
<786> WRONG!!!
$val = oct($val) if $val =~ /^0/;
<788> WRONG!!! WRONG!!! WRONG!!!
$dec_perms = (stat("filename"))[2] & 07777;
$oct_perm_str = sprintf "%o", $perms;
<798>
open(my $fh, '<', "input.txt") or die $!;
<800>
open(my $fh, '>', "output.txt") or die $!;
<813>
open(my $fh, "<:encoding(UTF-8)", "filename")
|| die "can't open UTF-8 encoded filename: $!";
<819>
open(my $tmp, "+>", undef) or die ...
<822> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
open($fh, '>', \$variable) || ..
<824> WRONG!!!
close STDOUT;
open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";
<826> WRONG!!!
$ARTICLE = 100;
open ARTICLE or die "Can't find article $ARTICLE: $!\n";
while (<ARTICLE>) {...
<827>
open(LOG, '>>/usr/spool/news/twitlog'); # (log is reserved)
# if the open fails, output is discarded
<828>
open(my $dbase, '+<', 'dbase.mine') # open for update
or die "Can't open 'dbase.mine' for update: $!";
<829>
open(my $dbase, '+<dbase.mine') # ditto
or die "Can't open 'dbase.mine' for update: $!";
<830> WRONG!!!
open(ARTICLE, '-|', "caesar <$article") # decrypt article
or die "Can't start caesar: $!";
<831> WRONG!!!
open(ARTICLE, "caesar <$article |") # ditto
or die "Can't start caesar: $!";
<832>
open(EXTRACT, "|sort >Tmp$$") # $$ is our process id
or die "Can't start sort: $!";
<833> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
# in-memory files
open(MEMORY,'>', \$var)
or die "Can't open memory file: $!";
print MEMORY "foo!\n"; # output will appear in $var
<834>
# process argument list of files along with any includes
<835> WRONG!!!
foreach $file (@ARGV) {
process($file, 'fh00');
}
<836>
sub process {
my($filename, $input) = @_;
$input++; # this is a string increment
unless (open($input, $filename)) {
print STDERR "Can't open $filename: $!\n";
return;
}
<837>
local $_;
while (<$input>) { # note use of indirection
if (/^#include "(.*)"/) {
process($1, $input);
next;
}
#... # whatever
}
}
<841> WRONG!!!
#!/usr/bin/perl
open my $oldout, ">&STDOUT" or die "Can't dup STDOUT: $!";
open OLDERR, ">&", \*STDERR or die "Can't dup STDERR: $!";
<842>
open STDOUT, '>', "foo.out" or die "Can't redirect STDOUT: $!";
open STDERR, ">&STDOUT" or die "Can't dup STDOUT: $!";
<843>
select STDERR; $| = 1; # make unbuffered
select STDOUT; $| = 1; # make unbuffered
<844>
print STDOUT "stdout 1\n"; # this works for
print STDERR "stderr 1\n"; # subprocesses too
<845> WRONG!!!
open STDOUT, ">&", $oldout or die "Can't dup \$oldout: $!";
open STDERR, ">&OLDERR" or die "Can't dup OLDERR: $!";
<846>
print STDOUT "stdout 2\n";
print STDERR "stderr 2\n";
<848> WRONG!!! WRONG!!!
# open for input, reusing the fileno of $fd
open(FILEHANDLE, "<&=$fd")
<850> WRONG!!! WRONG!!!
open(FILEHANDLE, "<&=", $fd)
<852> WRONG!!! WRONG!!! WRONG!!!
# open for append, using the fileno of OLDFH
open(FH, ">>&=", OLDFH)
<854> WRONG!!! WRONG!!!
open(FH, ">>&=OLDFH")
<860> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
open(FOO, "|tr '[a-z]' '[A-Z]'");
open(FOO, '|-', "tr '[a-z]' '[A-Z]'");
open(FOO, '|-') || exec 'tr', '[a-z]', '[A-Z]';
open(FOO, '|-', "tr", '[a-z]', '[A-Z]');
<861> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
open(FOO, "cat -n '$file'|");
open(FOO, '-|', "cat -n '$file'");
open(FOO, '-|') || exec 'cat', '-n', $file;
open(FOO, '-|', "cat", '-n', $file);
<868> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$filename =~ s/(.*\.gz)\s*$/gzip -dc < $1|/;
open(FH, $filename) or die "Can't open $filename: $!";
<870> WRONG!!! WRONG!!!
open(FOO, '<', $file);
<872> WRONG!!! WRONG!!!
$file =~ s#^(\s)#./$1#;
open(FOO, "< $file\0");
<874> WRONG!!!
open IN, $ARGV[0];
<876> WRONG!!!
open IN, '<', $ARGV[0];
<879> WRONG!!! WRONG!!! WRONG!!!
use IO::Handle;
sysopen(HANDLE, $path, O_RDWR|O_CREAT|O_EXCL)
or die "sysopen $path: $!";
$oldfh = select(HANDLE); $| = 1; select($oldfh);
print HANDLE "stuff $$\n";
seek(HANDLE, 0, 0);
print "File contains: ", <HANDLE>;
<881>
use IO::File;
#...
sub read_myfile_munged {
my $ALL = shift;
my $handle = IO::File->new;
open($handle, "myfile") or die "myfile: $!";
$first = <$handle>
or return (); # Automatically closed here.
mung $first or die "mung failed"; # Or here.
return $first, <$handle> if $ALL; # Or here.
$first; # Or here.
}
<897>
our $foo;
our($bar, $baz);
<899>
package Foo;
our $bar; # declares $Foo::bar for rest of lexical scope
$bar = 20;
<900> WRONG!!!
package Bar;
print $bar; # prints 20, as it refers to $Foo::bar
<902>
use warnings;
package Foo;
our $bar; # declares $Foo::bar for rest of lexical scope
$bar = 20;
<903>
package Bar;
our $bar = 30; # declares $Bar::bar for rest of lexical scope
print $bar; # prints 30
<904>
our $bar; # emits warning but has no other effect
print $bar; # still prints 30
<911>
a A string with arbitrary binary data, will be null padded.
A A text (ASCII) string, will be space padded.
Z A null-terminated (ASCIZ) string, will be null padded.
<912>
b A bit string (ascending bit order inside each byte, like vec()).
B A bit string (descending bit order inside each byte).
h A hex string (low nybble first).
H A hex string (high nybble first).
<913>
c A signed char (8-bit) value.
C An unsigned char (octet) value.
W An unsigned char value (can be greater than 255).
<914>
s A signed short (16-bit) value.
S An unsigned short value.
<915>
l A signed long (32-bit) value.
L An unsigned long value.
<916>
q A signed quad (64-bit) value.
Q An unsigned quad value.
(Quads are available only if your system supports 64-bit
integer values _and_ if Perl has been compiled to support those.
Raises an exception otherwise.)
<917>
i A signed integer value.
I A unsigned integer value.
(This 'integer' is _at_least_ 32 bits wide. Its exact
size depends on what a local C compiler calls 'int'.)
<918>
n An unsigned short (16-bit) in "network" (big-endian) order.
N An unsigned long (32-bit) in "network" (big-endian) order.
v An unsigned short (16-bit) in "VAX" (little-endian) order.
V An unsigned long (32-bit) in "VAX" (little-endian) order.
<919>
j A Perl internal signed integer value (IV).
J A Perl internal unsigned integer value (UV).
<920>
f A single-precision float in native format.
d A double-precision float in native format.
<921>
F A Perl internal floating-point value (NV) in native format
D A float of long-double precision in native format.
(Long doubles are available only if your system supports long
double values _and_ if Perl has been compiled to support those.
Raises an exception otherwise.)
<922>
p A pointer to a null-terminated string.
P A pointer to a structure (fixed-length string).
<923>
u A uuencoded string.
U A Unicode character number. Encodes to a character in character mode
and UTF-8 (or UTF-EBCDIC in EBCDIC platforms) in byte mode.
<924>
w A BER compressed integer (not an ASN.1 BER, see perlpacktut for
details). Its bytes represent an unsigned integer in base 128,
most significant digit first, with as few digits as possible. Bit
eight (the high bit) is set on each byte except the last.
<925>
x A null byte (a.k.a ASCII NUL, "\000", chr(0))
X Back up a byte.
@ Null-fill or truncate to absolute position, counted from the
start of the innermost ()-group.
. Null-fill or truncate to absolute position specified by the value.
( Start of a ()-group.
<927>
! sSlLiI Forces native (short, long, int) sizes instead
of fixed (16-/32-bit) sizes.
<928>
xX Make x and X act as alignment commands.
<929>
nNvV Treat integers as signed instead of unsigned.
<930>
@. Specify position as byte offset in the internal
representation of the packed string. Efficient but
dangerous.
<931>
> sSiIlLqQ Force big-endian byte-order on the type.
jJfFdDpP (The "big end" touches the construct.)
<932>
< sSiIlLqQ Force little-endian byte-order on the type.
jJfFdDpP (The "little end" touches the construct.)
<986>
unpack("W/a", "\004Gurusamy") gives ("Guru")
unpack("a3/A A*", "007 Bond J ") gives (" Bond", "J")
unpack("a3 x2 /A A*", "007: Bond, J.") gives ("Bond, J", ".")
<987>
pack("n/a* w/a","hello,","world") gives "\000\006hello,\005world"
pack("a/W2", ord("a") .. ord("z")) gives "2ab"
<992>
printf "format s is %d, s! is %d\n",
length pack("s"), length pack("s!");
<993>
printf "format l is %d, l! is %d\n",
length pack("l"), length pack("l!");
<996>
$ perl -V:{short,int,long{,long}}size
shortsize='2';
intsize='4';
longsize='4';
longlongsize='8';
<998>
use Config;
print $Config{shortsize}, "\n";
print $Config{intsize}, "\n";
print $Config{longsize}, "\n";
print $Config{longlongsize}, "\n";
<1002>
0x12 0x34 0x56 0x78 # big-endian
0x78 0x56 0x34 0x12 # little-endian
<1006>
0x56 0x78 0x12 0x34
0x34 0x12 0x78 0x56
<1008>
printf("%#02x ", $_) for unpack("W*", pack L=>0x12345678);
<1010>
use Config;
print "$Config{byteorder}\n";
<1012>
$ perl -V:byteorder
<1038>
pack("@1A((@2A)@3A)", qw[X Y Z])
<1042>
struct {
char c; /* one signed, 8-bit character */
double d;
char cc[2];
}
<1053> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$foo = pack("WWWW",65,66,67,68);
# foo eq "ABCD"
$foo = pack("W4",65,66,67,68);
# same thing
$foo = pack("W4",0x24b6,0x24b7,0x24b8,0x24b9);
# same thing with Unicode circled letters.
$foo = pack("U4",0x24b6,0x24b7,0x24b8,0x24b9);
# same thing with Unicode circled letters. You don't get the UTF-8
# bytes because the U at the start of the format caused a switch to
# U0-mode, so the UTF-8 bytes get joined into characters
$foo = pack("C0U4",0x24b6,0x24b7,0x24b8,0x24b9);
# foo eq "\xe2\x92\xb6\xe2\x92\xb7\xe2\x92\xb8\xe2\x92\xb9"
# This is the UTF-8 encoding of the string in the previous example
<1054> WRONG!!!
$foo = pack("ccxxcc",65,66,67,68);
# foo eq "AB\0\0CD"
<1055> WRONG!!!
# NOTE: The examples above featuring "W" and "c" are true
# only on ASCII and ASCII-derived systems such as ISO Latin 1
# and UTF-8. On EBCDIC systems, the first example would be
# $foo = pack("WWWW",193,194,195,196);
<1056> WRONG!!!
$foo = pack("s2",1,2);
# "\001\000\002\000" on little-endian
# "\000\001\000\002" on big-endian
<1057> WRONG!!!
$foo = pack("a4","abcd","x","y","z");
# "abcd"
<1058> WRONG!!!
$foo = pack("aaaa","abcd","x","y","z");
# "axyz"
<1059> WRONG!!!
$foo = pack("a14","abcdefg");
# "abcdefg\0\0\0\0\0\0\0"
<1060> WRONG!!!
$foo = pack("i9pl", gmtime);
# a real struct tm (on my system anyway)
<1061> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$utmp_template = "Z8 Z8 Z16 L";
$utmp = pack($utmp_template, @utmp1);
# a struct utmp (BSDish)
<1062> WRONG!!! WRONG!!!
@utmp2 = unpack($utmp_template, $utmp);
# "@utmp1" eq "@utmp2"
<1063>
sub bintodec {
unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
<1064> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$foo = pack('sx2l', 12, 34);
# short 12, two zero bytes padding, long 34
$bar = pack('s@4l', 12, 34);
# short 12, zero fill to position 4, long 34
# $foo eq $bar
$baz = pack('s.l', 12, 4, 34);
# short 12, zero fill to position 4, long 34
<1065> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$foo = pack('nN', 42, 4711);
# pack big-endian 16- and 32-bit unsigned integers
$foo = pack('S>L>', 42, 4711);
# exactly the same
$foo = pack('s<l<', -42, 4711);
# pack little-endian 16- and 32-bit signed integers
$foo = pack('(sl)<', -42, 4711);
# exactly the same
<1094> WRONG!!! WRONG!!! WRONG!!!
print { $files[$i] } "stuff\n";
print { $OK ? STDOUT : STDERR } "stuff\n";
<1105> WRONG!!! WRONG!!! WRONG!!!
for $value (LIST) {
$ARRAY[++$#ARRAY] = $value;
}
<1120>
my $sentence = 'The quick brown fox jumped over the lazy dog';
my $substring = 'quick.*?fox';
$sentence =~ s{$substring}{big bad wolf};
<1123>
my $sentence = 'The quick brown fox jumped over the lazy dog';
my $substring = 'quick.*?fox';
$sentence =~ s{\Q$substring\E}{big bad wolf};
<1125>
my $sentence = 'The quick brown fox jumped over the lazy dog';
my $substring = 'quick.*?fox';
my $quoted_substring = quotemeta($substring);
$sentence =~ s{$quoted_substring}{big bad wolf};
<1131>
int(rand(10))
<1143> WRONG!!! WRONG!!!
opendir(my $dh, $some_dir) || die "can't opendir $some_dir: $!";
@dots = grep { /^\./ && -f "$some_dir/$_" } readdir($dh);
closedir $dh;
<1145> WRONG!!! WRONG!!!
opendir(my $dh, $some_dir) || die;
while(readdir $dh) {
print "$some_dir/$_\n";
}
closedir $dh;
<1151> WRONG!!!
$line = <STDIN>;
$line = readline(*STDIN); # same thing
<1153> WRONG!!!
while ( ! eof($fh) ) {
defined( $_ = <$fh> ) or die "readline failed: $!";
...
}
<1155>
foreach my $arg (@ARGV) {
open(my $fh, $arg) or warn "Can't open $arg: $!";
<1156> WRONG!!! WRONG!!!
while ( ! eof($fh) ) {
defined( $_ = <$fh> )
or die "readline failed for $arg: $!";
...
}
}
<1169> WRONG!!! WRONG!!! WRONG!!!
# a simpleminded Pascal comment stripper
# (warning: assumes no { or } in strings)
LINE: while (<STDIN>) {
while (s|({.*}.*){.*}|$1 |) {}
s|{.*}| |;
if (s|{.*| |) {
$front = $_;
while (<STDIN>) {
if (/}/) { # end of comment?
s|^|$front\{|;
redo LINE;
}
}
}
print;
}
<1176>
SCALAR
ARRAY
HASH
CODE
REF
GLOB
LVALUE
FORMAT
IO
VSTRING
Regexp
<1178> WRONG!!! WRONG!!!
if (ref($r) eq "HASH") {
print "r is a reference to a hash.\n";
}
unless (ref($r)) {
print "r is not a reference at all.\n";
}
<1192>
require v5.6.1; # run time version check
require 5.6.1; # ditto
require 5.006_001; # ditto; preferred for backwards compatibility
<1194> WRONG!!!
sub require {
my ($filename) = @_;
if (exists $INC{$filename}) {
return 1 if $INC{$filename};
die "Compilation failed in require";
}
my ($realfilename,$result);
ITER: {
foreach $prefix (@INC) {
$realfilename = "$prefix/$filename";
if (-f $realfilename) {
$INC{$filename} = $realfilename;
$result = do $realfilename;
last ITER;
}
}
die "Can't find $filename in \@INC";
}
if ($@) {
$INC{$filename} = undef;
die $@;
} elsif (!$result) {
delete $INC{$filename};
die "$filename did not return true value";
} else {
return $result;
}
}
<1199>
require Foo::Bar; # a splendid bareword
<1202> WRONG!!!
$class = 'Foo::Bar';
require $class; # $class is not a bareword
#or
require "Foo::Bar"; # not a bareword because of the ""
<1204> WRONG!!!
eval "require $class";
<1219>
push @INC, \&my_sub;
sub my_sub {
my ($coderef, $filename) = @_; # $coderef is \&my_sub
...
}
<1221>
push @INC, [ \&my_sub, $x, $y, ... ];
sub my_sub {
my ($arrayref, $filename) = @_;
# Retrieve $x, $y, ...
my @parameters = @$arrayref[1..$#$arrayref];
...
}
<1223>
# In Foo.pm
package Foo;
sub new { ... }
sub Foo::INC {
my ($self, $filename) = @_;
...
}
<1224>
# In the main program
push @INC, Foo->new(...);
<1230>
reset 'X'; # reset all X variables
reset 'a-z'; # reset lower case variables
reset; # just reset ?one-time? searches
<1238>
print join(", ", reverse "world", "Hello"); # Hello, world
<1239>
print scalar reverse "dlrow ,", "olleH"; # Hello, world
<1241> WRONG!!!
$_ = "dlrow ,olleH";
print reverse; # No output, list context
print scalar reverse; # Hello, world
<1244> WRONG!!! WRONG!!!
%by_name = reverse %by_address; # Invert the hash
<1263> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
@counts = ( scalar @a, scalar @b, scalar @c );
<1267> WRONG!!! WRONG!!!
print uc(scalar(&foo,$bar)),$baz;
<1269> WRONG!!! WRONG!!!
&foo;
print(uc($bar),$baz);
<1276> WRONG!!!
seek(TEST,0,1);
<1279> WRONG!!! WRONG!!! WRONG!!!
for (;;) {
for ($curpos = tell(FILE); $_ = <FILE>;
$curpos = tell(FILE)) {
# search for some stuff and put it into files
}
sleep($for_a_while);
seek(FILE, $curpos, 0);
}
<1285> WRONG!!! WRONG!!!
select(REPORT1);
$^ = 'report1_top';
select(REPORT2);
$^ = 'report2_top';
<1287> WRONG!!! WRONG!!! WRONG!!!
$oldfh = select(STDERR); $| = 1; select($oldfh);
<1289>
use IO::Handle;
STDERR->autoflush(1);
<1292> WRONG!!! WRONG!!! WRONG!!!
$rin = $win = $ein = '';
vec($rin,fileno(STDIN),1) = 1;
vec($win,fileno(STDOUT),1) = 1;
$ein = $rin | $win;
<1294> WRONG!!!
sub fhbits {
my(@fhlist) = split(' ',$_[0]);
my($bits);
for (@fhlist) {
vec($bits,fileno($_),1) = 1;
}
$bits;
}
$rin = fhbits('STDIN TTY SOCK');
<1296> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
($nfound,$timeleft) =
select($rout=$rin, $wout=$win, $eout=$ein, $timeout);
<1298> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$nfound = select($rout=$rin, $wout=$win, $eout=$ein, undef);
<1302>
select(undef, undef, undef, 0.25);
<1309>
use IPC::SysV;
<1315> WRONG!!! WRONG!!! WRONG!!!
$semop = pack("s!3", $semnum, -1, 0);
die "Semaphore trouble: $!\n" unless semop($semid, $semop);
<1328> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
use Socket qw(IPPROTO_TCP TCP_NODELAY);
setsockopt($socket, IPPROTO_TCP, TCP_NODELAY, 1);
<1336>
use IPC::SysV;
<1345> WRONG!!! WRONG!!! WRONG!!!
shutdown(SOCKET, 0); # I/we have stopped reading data
shutdown(SOCKET, 1); # I/we have stopped writing data
shutdown(SOCKET, 2); # I/we have stopped using this socket
<1352>
sub asin { atan2($_[0], sqrt(1 - $_[0] * $_[0])) }
<1357>
eval {
local $SIG{ALARM} = sub { die "Alarm!\n" };
sleep;
};
die $@ unless $@ eq "Alarm!\n";
<1369> WRONG!!! WRONG!!!
use Socket;
socketpair(Rdr, Wtr, AF_UNIX, SOCK_STREAM, PF_UNSPEC);
shutdown(Rdr, 1); # no more writing for reader
shutdown(Wtr, 0); # no more reading for writer
<1383> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
# sort lexically
@articles = sort @files;
# same thing, but with explicit sort routine
@articles = sort {$a cmp $b} @files;
# now case-insensitively
@articles = sort {uc($a) cmp uc($b)} @files;
# same thing in reversed order
@articles = sort {$b cmp $a} @files;
# sort numerically ascending
@articles = sort {$a <=> $b} @files;
# sort numerically descending
@articles = sort {$b <=> $a} @files;
# this sorts the %age hash by value instead of key
# using an in-line function
@eldest = sort { $age{$b} <=> $age{$a} } keys %age;
# sort using explicit subroutine name
sub byage {
$age{$a} <=> $age{$b}; # presuming numeric
}
@sortedclass = sort byage @class;
sub backwards { $b cmp $a }
@harry = qw(dog cat x Cain Abel);
@george = qw(gone chased yz Punished Axed);
print sort @harry;
# prints AbelCaincatdogx
print sort backwards @harry;
# prints xdogcatCainAbel
print sort @george, 'to', @harry;
# prints AbelAxedCainPunishedcatchaseddoggonetoxyz
<1384>
# inefficiently sort by descending numeric compare using
# the first integer after the first = sign, or the
# whole record case-insensitively otherwise
<1385> WRONG!!!
my @new = sort {
($b =~ /=(\d+)/)[0] <=> ($a =~ /=(\d+)/)[0]
||
uc($a) cmp uc($b)
} @old;
<1386> WRONG!!! WRONG!!! WRONG!!!
# same thing, but much more efficiently;
# we'll build auxiliary indices instead
# for speed
my @nums = @caps = ();
for (@old) {
push @nums, ( /=(\d+)/ ? $1 : undef );
push @caps, uc($_);
}
<1387> WRONG!!! WRONG!!! WRONG!!!
my @new = @old[ sort {
$nums[$b] <=> $nums[$a]
||
$caps[$a] cmp $caps[$b]
} 0..$#old
];
<1388> WRONG!!! WRONG!!!
# same thing, but without any temps
@new = map { $_->[0] }
sort { $b->[1] <=> $a->[1]
||
$a->[2] cmp $b->[2]
} map { [$_, /=(\d+)/, uc($_)] } @old;
<1389> WRONG!!! WRONG!!!
# using a prototype allows you to use any comparison subroutine
# as a sort subroutine (including other package's subroutines)
package other;
sub backwards ($$) { $_[1] cmp $_[0]; } # $a and $b are not set here
package main;
@new = sort other::backwards @old;
# guarantee stability, regardless of algorithm
use sort 'stable';
@new = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @old;
# force use of mergesort (not portable outside Perl 5.8)
use sort '_mergesort'; # note discouraging _
@new = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @old;
<1391> WRONG!!! WRONG!!!
@contact = sort { $a cmp $b } find_records @key;
@contact = sort +find_records(@key);
@contact = sort &find_records(@key);
@contact = sort(find_records(@key));
<1393> WRONG!!! WRONG!!!
@contact = sort { find_records() } @key;
@contact = sort find_records(@key);
@contact = sort(find_records @key);
@contact = sort(find_records (@key));
<1395> WRONG!!! WRONG!!!
@articles = sort {$b <=> $a} @files;
<1397> WRONG!!! WRONG!!!
@articles = sort {$FooPack::b <=> $FooPack::a} @files;
<1400> WRONG!!! WRONG!!!
@result = sort { $a <=> $b } grep { $_ == $_ } @input;
<1408> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
push(@a,$x,$y) splice(@a,@a,0,$x,$y)
pop(@a) splice(@a,-1)
shift(@a) splice(@a,0,1)
unshift(@a,$x,$y) splice(@a,0,0,$x,$y)
$a[$i] = $y splice(@a,$i,1,$y)
<1410>
sub aeq { # compare two list values
my(@a) = splice(@_,0,shift);
my(@b) = splice(@_,0,shift);
return 0 unless @a == @b; # same len?
while (@a) {
return 0 if pop(@a) ne pop(@b);
}
return 1;
}
if (&aeq($len,@foo[1..$len],0+@bar,@bar)) { ... }
<1420>
print join(':', split(/ */, 'hi there')), "\n";
<1423>
print join(':', split(//, 'hi there')), "\n";
<1426>
print join(':', split(/(?=\w)/, 'hi there!'));
<1428>
print join(':', split(//, 'hi there!', -1)), "\n";
print join(':', split(/\W/, 'hi there!', -1)), "\n";
<1431> WRONG!!!
($login, $passwd, $remainder) = split(/:/, $_, 3);
<1434>
split(/([,-])/, "1-10,20", 3);
<1436>
(1, '-', 10, ',', 20)
<1438> WRONG!!! WRONG!!!
$header =~ s/\n(?=\s)//g; # fix continuation lines
%hdrs = (UNIX_FROM => split /^(\S*?):\s*/m, $header);
<1443> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
open(PASSWD, '/etc/passwd');
while (<PASSWD>) {
chomp;
($login, $passwd, $uid, $gid,
$gcos, $home, $shell) = split(/:/);
#...
}
<1445> WRONG!!!
@fields = split /(A)|B/, "1A2B3";
# @fields is (1, 'A', 2, undef, 3)
<1449> WRONG!!! WRONG!!!
# Format number with up to 8 leading zeroes
$result = sprintf("%08d", $number);
<1450> WRONG!!! WRONG!!!
# Round number to 3 digits after decimal point
$rounded = sprintf("%.3f", $number);
<1454>
%% a percent sign
%c a character with the given number
%s a string
%d a signed integer, in decimal
%u an unsigned integer, in decimal
%o an unsigned integer, in octal
%x an unsigned integer, in hexadecimal
%e a floating-point number, in scientific notation
%f a floating-point number, in fixed decimal notation
%g a floating-point number, in %e or %f notation
<1456>
%X like %x, but using upper-case letters
%E like %e, but using an upper-case "E"
%G like %g, but with an upper-case "E" (if applicable)
%b an unsigned integer, in binary
%B like %b, but using an upper-case "B" with the # flag
%p a pointer (outputs the Perl value's address in hexadecimal)
%n special: *stores* the number of characters output so far
into the next variable in the parameter list
<1458>
%i a synonym for %d
%D a synonym for %ld
%U a synonym for %lu
%O a synonym for %lo
%F a synonym for %f
<1464>
printf '%2$d %1$d', 12, 34; # prints "34 12"
printf '%3$d %d %1$d', 1, 2, 3; # prints "3 1 1"
<1467>
space prefix non-negative number with a space
+ prefix non-negative number with a plus sign
- left-justify within the field
0 use zeros, not spaces, to right-justify
# ensure the leading "0" for any octal,
prefix non-zero hexadecimal with "0x" or "0X",
prefix non-zero binary with "0b" or "0B"
<1469>
printf '<% d>', 12; # prints "< 12>"
printf '<%+d>', 12; # prints "<+12>"
printf '<%6s>', 12; # prints "< 12>"
printf '<%-6s>', 12; # prints "<12 >"
printf '<%06s>', 12; # prints "<000012>"
printf '<%#o>', 12; # prints "<014>"
printf '<%#x>', 12; # prints "<0xc>"
printf '<%#X>', 12; # prints "<0XC>"
printf '<%#b>', 12; # prints "<0b1100>"
printf '<%#B>', 12; # prints "<0B1100>"
<1471>
printf '<%+ d>', 12; # prints "<+12>"
printf '<% +d>', 12; # prints "<+12>"
<1473>
printf '<%#.5o>', 012; # prints "<00012>"
printf '<%#.5o>', 012345; # prints "<012345>"
printf '<%#.0o>', 0; # prints "<0>"
<1476>
printf "%vd", "AB\x{100}"; # prints "65.66.256"
printf "version is v%vd\n", $^V; # Perl's version
<1478> WRONG!!! WRONG!!!
printf "address is %*vX\n", ":", $addr; # IPv6 address
printf "bits are %0*v8b\n", " ", $bits; # random bitstring
<1480> WRONG!!!
printf '%*4$vX %*4$vX %*4$vX', @addr[1..3], ":"; # 3 IPv6 addresses
<1483>
printf '<%s>', "a"; # prints "<a>"
printf '<%6s>', "a"; # prints "< a>"
printf '<%*s>', 6, "a"; # prints "< a>"
printf '<%*2$s>', "a", 6; # prints "< a>"
printf '<%2s>', "long"; # prints "<long>" (does not truncate)
<1487>
# these examples are subject to system-specific variation
printf '<%f>', 1; # prints "<1.000000>"
printf '<%.1f>', 1; # prints "<1.0>"
printf '<%.0f>', 1; # prints "<1>"
printf '<%e>', 10; # prints "<1.000000e+01>"
printf '<%.1e>', 10; # prints "<1.0e+01>"
<1489>
# These examples are subject to system-specific variation.
printf '<%g>', 1; # prints "<1>"
printf '<%.10g>', 1; # prints "<1>"
printf '<%g>', 100; # prints "<100>"
printf '<%.1g>', 100; # prints "<1e+02>"
printf '<%.2g>', 100.01; # prints "<1e+02>"
printf '<%.5g>', 100.01; # prints "<100.01>"
printf '<%.4g>', 100.01; # prints "<100>"
<1491>
printf '<%.6d>', 1; # prints "<000001>"
printf '<%+.6d>', 1; # prints "<+000001>"
printf '<%-10.6d>', 1; # prints "<000001 >"
printf '<%10.6d>', 1; # prints "< 000001>"
printf '<%010.6d>', 1; # prints "< 000001>"
printf '<%+10.6d>', 1; # prints "< +000001>"
<1492>
printf '<%.6x>', 1; # prints "<000001>"
printf '<%#.6x>', 1; # prints "<0x000001>"
printf '<%-10.6x>', 1; # prints "<000001 >"
printf '<%10.6x>', 1; # prints "< 000001>"
printf '<%010.6x>', 1; # prints "< 000001>"
printf '<%#10.6x>', 1; # prints "< 0x000001>"
<1494>
printf '<%.5s>', "truncated"; # prints "<trunc>"
printf '<%10.5s>', "truncated"; # prints "< trunc>"
<1496>
printf '<%.6x>', 1; # prints "<000001>"
printf '<%.*x>', 6, 1; # prints "<000001>"
<1498>
printf '<%.*s>', 7, "string"; # prints "<string>"
printf '<%.*s>', 3, "string"; # prints "<str>"
printf '<%.*s>', 0, "string"; # prints "<>"
printf '<%.*s>', -1, "string"; # prints "<string>"
<1499>
printf '<%.*d>', 1, 0; # prints "<0>"
printf '<%.*d>', 0, 0; # prints "<>"
printf '<%.*d>', -1, 0; # prints "<0>"
<1501>
printf "<%.*2$x>", 1, 6; # INVALID, but in future will print "<000001>"
<1504>
l interpret integer as C type "long" or "unsigned long"
h interpret integer as C type "short" or "unsigned short"
q, L or ll interpret integer as C type "long long", "unsigned long long".
or "quads" (typically 64-bit integers)
<1506>
use Config;
if ($Config{use64bitint} eq "define" || $Config{longsize} >= 8) {
print "Nice quads!\n";
}
<1508>
use Config;
print "long doubles\n" if $Config{d_longdbl} eq "define";
<1510>
use Config;
if ($Config{uselongdouble} eq "define") {
print "long doubles by default\n";
}
<1512>
use Config;
($Config{doublesize} == $Config{longdblsize}) &&
print "doubles are long doubles\n";
<1517> WRONG!!! WRONG!!! WRONG!!!
printf "<%*.*s>", $a, $b, $c;
<1519> WRONG!!! WRONG!!!
printf "<%*1$.*s>", $a, $b;
<1522>
printf "%2\$d %d\n", 12, 34; # will print "34 12\n"
printf "%2\$d %d %d\n", 12, 34; # will print "34 12 34\n"
printf "%3\$d %d %d\n", 12, 34, 56; # will print "56 12 34\n"
printf "%2\$*3\$d %d\n", 12, 34, 3; # will print " 34 12\n"
<1528>
use Math::Complex;
print sqrt(-4); # prints 2i
<1539>
srand (time ^ $$ ^ unpack "%L*", `ps axww | gzip -f`);
<1542>
time ^ $$
<1544>
a^b == (a+1)^(b+1)
<1552> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
$atime,$mtime,$ctime,$blksize,$blocks)
= stat($filename);
<1554>
0 dev device number of filesystem
1 ino inode number
2 mode file mode (type and permissions)
3 nlink number of (hard) links to the file
4 uid numeric user ID of file's owner
5 gid numeric group ID of file's owner
6 rdev the device identifier (special files only)
7 size total size of file, in bytes
8 atime last access time in seconds since the epoch
9 mtime last modify time in seconds since the epoch
10 ctime inode change time in seconds since the epoch (*)
11 blksize preferred block size for file system I/O
12 blocks actual number of blocks allocated
<1558> WRONG!!! WRONG!!!
if (-x $file && (($d) = stat(_)) && $d < 0) {
print "$file is executable NFS file\n";
}
<1561> WRONG!!! WRONG!!!
$mode = (stat($filename))[2];
printf "Permissions are %04o\n", $mode & 07777;
<1564> WRONG!!! WRONG!!!
use File::stat;
$sb = stat($filename);
printf "File is %s, size is %s, perm %04o, mtime %s\n",
$filename, $sb->size, $sb->mode & 07777,
scalar localtime $sb->mtime;
<1566>
use Fcntl ':mode';
<1567> WRONG!!! WRONG!!!
$mode = (stat($filename))[2];
<1568> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$user_rwx = ($mode & S_IRWXU) >> 6;
$group_read = ($mode & S_IRGRP) >> 3;
$other_execute = $mode & S_IXOTH;
<1569> WRONG!!!
printf "Permissions are %04o\n", S_IMODE($mode), "\n";
<1570> WRONG!!! WRONG!!!
$is_setuid = $mode & S_ISUID;
$is_directory = S_ISDIR($mode);
<1572>
# Permissions: read, write, execute, for user, group, others.
<1573>
S_IRWXU S_IRUSR S_IWUSR S_IXUSR
S_IRWXG S_IRGRP S_IWGRP S_IXGRP
S_IRWXO S_IROTH S_IWOTH S_IXOTH
<1574>
# Setuid/Setgid/Stickiness/SaveText.
# Note that the exact meaning of these is system dependent.
<1575>
S_ISUID S_ISGID S_ISVTX S_ISTXT
<1576>
# File types. Not necessarily all are available on your system.
<1577>
S_IFREG S_IFDIR S_IFLNK S_IFBLK S_IFCHR S_IFIFO S_IFSOCK S_IFWHT S_ENFMT
<1578>
# The following are compatibility aliases for S_IRUSR, S_IWUSR, S_IXUSR.
<1579>
S_IREAD S_IWRITE S_IEXEC
<1581> WRONG!!!
S_IMODE($mode) the part of $mode containing the permission bits
and the setuid/setgid/sticky bits
<1582> WRONG!!!
S_IFMT($mode) the part of $mode containing the file type
which can be bit-anded with (for example) S_IFREG
or with the following functions
<1583>
# The operators -f, -d, -l, -b, -c, -p, and -S.
<1584> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
S_ISREG($mode) S_ISDIR($mode) S_ISLNK($mode)
S_ISBLK($mode) S_ISCHR($mode) S_ISFIFO($mode) S_ISSOCK($mode)
<1585>
# No direct -X operator counterpart, but for the first one
# the -g operator is often equivalent. The ENFMT stands for
# record flocking enforcement, a platform-dependent feature.
<1586> WRONG!!! WRONG!!!
S_ISENFMT($mode) S_ISWHT($mode)
<1598>
while (<>) {
study;
print ".IX foo\n" if /\bfoo\b/;
print ".IX bar\n" if /\bbar\b/;
print ".IX blurfl\n" if /\bblurfl\b/;
# ...
print;
}
<1601> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
$search = 'while (<>) { study;';
foreach $word (@words) {
$search .= "++\$seen{\$ARGV} if /\\b$word\\b/;\n";
}
$search .= "}";
@ARGV = @files;
undef $/;
eval $search; # this screams
$/ = "\n"; # put back to normal input delimiter
foreach $file (sort keys(%seen)) {
print $file, "\n";
}
<1612>
my $s = "The black cat climbed the green tree";
my $color = substr $s, 4, 5; # black
my $middle = substr $s, 4, -11; # black cat climbed the
my $end = substr $s, 14; # climbed the green tree
my $tail = substr $s, -4; # tree
my $z = substr $s, -4, 2; # tr
<1615>
my $name = 'fred';
substr($name, 4) = 'dy'; # $name is now 'freddy'
my $null = substr $name, 6, 2; # returns "" (no warning)
my $oops = substr $name, 7; # returns undef, with warning
substr($name, 7) = 'gap'; # raises an exception
<1617>
my $s = "The black cat climbed the green tree";
my $z = substr $s, 14, 7, "jumped from"; # climbed
# $s is now "The black cat jumped from the green tree"
<1619> WRONG!!!
$x = '1234';
for (substr($x,1,2)) {
$_ = 'a'; print $x,"\n"; # prints 1a4
$_ = 'xyz'; print $x,"\n"; # prints 1xyz4
$x = '56789';
$_ = 'pq'; print $x,"\n"; # prints 5pq9
}
<1623> WRONG!!!
$symlink_exists = eval { symlink("",""); 1 };
<1626> WRONG!!!
require 'syscall.ph'; # may need to run h2ph
$s = "hi there\n";
syscall(&SYS_write, fileno(STDOUT), $s, length $s);
<1653>
use Fcntl 'SEEK_CUR';
sub systell { sysseek($_[0], 0, SEEK_CUR) }
<1663> WRONG!!!
@args = ("command", "arg1", "arg2");
system(@args) == 0
or die "system @args failed: $?"
<1665>
if ($? == -1) {
print "failed to execute: $!\n";
}
elsif ($? & 127) {
printf "child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without';
}
else {
printf "child exited with value %d\n", $? >> 8;
}
<1687> WRONG!!! WRONG!!! WRONG!!!
# print out history file offsets
use NDBM_File;
tie(%HIST, 'NDBM_File', '/usr/lib/news/history', 1, 0);
while (($key,$val) = each %HIST) {
print $key, ' = ', unpack('L',$val), "\n";
}
untie(%HIST);
<1689>
TIEHASH classname, LIST
FETCH this, key
STORE this, key, value
DELETE this, key
CLEAR this
EXISTS this, key
FIRSTKEY this
NEXTKEY this, lastkey
SCALAR this
DESTROY this
UNTIE this
<1691>
TIEARRAY classname, LIST
FETCH this, key
STORE this, key, value
FETCHSIZE this
STORESIZE this, count
CLEAR this
PUSH this, LIST
POP this
SHIFT this
UNSHIFT this, LIST
SPLICE this, offset, length, LIST
EXTEND this, count
DESTROY this
UNTIE this
<1693>
TIEHANDLE classname, LIST
READ this, scalar, length, offset
READLINE this
GETC this
WRITE this, scalar, length, offset
PRINT this, LIST
PRINTF this, format, LIST
BINMODE this
EOF this
FILENO this
SEEK this, position, whence
TELL this
OPEN this, mode, LIST
CLOSE this
DESTROY this
UNTIE this
<1695>
TIESCALAR classname, LIST
FETCH this,
STORE this, value
DESTROY this
UNTIE this
<1707> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
($user,$system,$cuser,$csystem) = times;
<1737> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
undef $foo;
undef $bar{'blurfl'}; # Compare to: delete $bar{'blurfl'};
undef @ary;
undef %hash;
undef &mysub;
undef *xyz; # destroys $xyz, @xyz, %xyz, &xyz, etc.
return (wantarray ? (undef, $errmsg) : undef) if $they_blew_it;
select undef, undef, undef, 0.25;
($a, $b, undef, $c) = &foo; # Ignore third value returned
<1742> WRONG!!!
my $unlinked = unlink 'a', 'b', 'c';
unlink @goners;
unlink glob "*.bak";
<1744> WRONG!!! WRONG!!!
foreach my $file ( @goners ) {
unlink $file or warn "Could not unlink $file: $!";
}
<1753>
sub substr {
my($what,$where,$howmuch) = @_;
unpack("x$where a$howmuch", $what);
}
<1755>
sub ordinal { unpack("W",$_[0]); } # same as ord()
<1758> WRONG!!!
$checksum = do {
local $/; # slurp!
unpack("%32W*",<>) % 65535;
};
<1760> WRONG!!! WRONG!!!
$setbits = unpack("%32b*", $selectmask);
<1768>
unshift(@ARGV, '-e') unless $ARGV[0] =~ /^-/;
<1777>
BEGIN { require Module; Module->import( LIST ); }
<1781>
use v5.6.1; # compile time version check
use 5.6.1; # ditto
use 5.006_001; # ditto; preferred for backwards compatibility
<1786>
use Module ();
<1788>
BEGIN { require Module }
<1792>
use constant;
use diagnostics;
use integer;
use sigtrap qw(SEGV BUS);
use strict qw(subs vars refs);
use subs qw(afunc blurfl);
use warnings qw(all);
use sort qw(stable _quicksort _mergesort);
<1795>
use if $] < 5.008, "utf8";
use if WANT_WARNINGS, warnings => qw(all);
<1797>
no integer;
no strict 'refs';
no warnings;
<1802> WRONG!!! WRONG!!! WRONG!!!
#!/usr/bin/perl
$atime = $mtime = time;
utime $atime, $mtime, @ARGV;
<1804> WRONG!!!
for $file (@ARGV) {
utime(undef, undef, $file)
|| warn "couldn't touch $file: $!";
}
<1814> WRONG!!! WRONG!!!
for (values %hash) { s/foo/bar/g } # modifies %hash values
for (@hash{keys %hash}) { s/foo/bar/g } # same
<1816> WRONG!!! WRONG!!!
for (values $hashref) { ... }
for (values $obj->get_arrayref) { ... }
<1825> WRONG!!! WRONG!!! WRONG!!! WRONG!!!
vec($image, $max_x * $x + $y, 8) = 3;
<1830>
my $foo = '';
vec($foo, 0, 32) = 0x5065726C; # 'Perl'
<1831>
# $foo eq "Perl" eq "\x50\x65\x72\x6C", 32 bits
print vec($foo, 0, 8); # prints 80 == 0x50 == ord('P')
<1832>
vec($foo, 2, 16) = 0x5065; # 'PerlPe'
vec($foo, 3, 16) = 0x726C; # 'PerlPerl'
vec($foo, 8, 8) = 0x50; # 'PerlPerlP'
vec($foo, 9, 8) = 0x65; # 'PerlPerlPe'
vec($foo, 20, 4) = 2; # 'PerlPerlPe' . "\x02"
vec($foo, 21, 4) = 7; # 'PerlPerlPer'
# 'r' is "\x72"
vec($foo, 45, 2) = 3; # 'PerlPerlPer' . "\x0c"
vec($foo, 93, 1) = 1; # 'PerlPerlPer' . "\x2c"
vec($foo, 94, 1) = 1; # 'PerlPerlPerl'
# 'l' is "\x6c"
<1834> WRONG!!! WRONG!!! WRONG!!!
$bits = unpack("b*", $vector);
@bits = split(//, unpack("b*", $vector));
<1837>
#!/usr/bin/perl -wl
<1838>
print <<'EOT';
0 1 2 3
unpack("V",$_) 01234567890123456789012345678901
------------------------------------------------------------------
EOT
<1839> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
for $w (0..3) {
$width = 2**$w;
for ($shift=0; $shift < $width; ++$shift) {
for ($off=0; $off < 32/$width; ++$off) {
$str = pack("B*", "0"x32);
$bits = (1<<$shift);
vec($str, $off, $width) = $bits;
$res = unpack("b*",$str);
$val = unpack("V", $str);
write;
}
}
}
<1840> WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!! WRONG!!!
format STDOUT =
vec($_,@#,@#) = @<< == @######### @>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
$off, $width, $bits, $val, $res
.
__END__
<1842>
0 1 2 3
unpack("V",$_) 01234567890123456789012345678901
------------------------------------------------------------------
vec($_, 0, 1) = 1 == 1 10000000000000000000000000000000
vec($_, 1, 1) = 1 == 2 01000000000000000000000000000000
vec($_, 2, 1) = 1 == 4 00100000000000000000000000000000
vec($_, 3, 1) = 1 == 8 00010000000000000000000000000000
vec($_, 4, 1) = 1 == 16 00001000000000000000000000000000
vec($_, 5, 1) = 1 == 32 00000100000000000000000000000000
vec($_, 6, 1) = 1 == 64 00000010000000000000000000000000
vec($_, 7, 1) = 1 == 128 00000001000000000000000000000000
vec($_, 8, 1) = 1 == 256 00000000100000000000000000000000
vec($_, 9, 1) = 1 == 512 00000000010000000000000000000000
vec($_,10, 1) = 1 == 1024 00000000001000000000000000000000
vec($_,11, 1) = 1 == 2048 00000000000100000000000000000000
vec($_,12, 1) = 1 == 4096 00000000000010000000000000000000
vec($_,13, 1) = 1 == 8192 00000000000001000000000000000000
vec($_,14, 1) = 1 == 16384 00000000000000100000000000000000
vec($_,15, 1) = 1 == 32768 00000000000000010000000000000000
vec($_,16, 1) = 1 == 65536 00000000000000001000000000000000
vec($_,17, 1) = 1 == 131072 00000000000000000100000000000000
vec($_,18, 1) = 1 == 262144 00000000000000000010000000000000
vec($_,19, 1) = 1 == 524288 00000000000000000001000000000000
vec($_,20, 1) = 1 == 1048576 00000000000000000000100000000000
vec($_,21, 1) = 1 == 2097152 00000000000000000000010000000000
vec($_,22, 1) = 1 == 4194304 00000000000000000000001000000000
vec($_,23, 1) = 1 == 8388608 00000000000000000000000100000000
vec($_,24, 1) = 1 == 16777216 00000000000000000000000010000000
vec($_,25, 1) = 1 == 33554432 00000000000000000000000001000000
vec($_,26, 1) = 1 == 67108864 00000000000000000000000000100000
vec($_,27, 1) = 1 == 134217728 00000000000000000000000000010000
vec($_,28, 1) = 1 == 268435456 00000000000000000000000000001000
vec($_,29, 1) = 1 == 536870912 00000000000000000000000000000100
vec($_,30, 1) = 1 == 1073741824 00000000000000000000000000000010
vec($_,31, 1) = 1 == 2147483648 00000000000000000000000000000001
vec($_, 0, 2) = 1 == 1 10000000000000000000000000000000
vec($_, 1, 2) = 1 == 4 00100000000000000000000000000000
vec($_, 2, 2) = 1 == 16 00001000000000000000000000000000
vec($_, 3, 2) = 1 == 64 00000010000000000000000000000000
vec($_, 4, 2) = 1 == 256 00000000100000000000000000000000
vec($_, 5, 2) = 1 == 1024 00000000001000000000000000000000
vec($_, 6, 2) = 1 == 4096 00000000000010000000000000000000
vec($_, 7, 2) = 1 == 16384 00000000000000100000000000000000
vec($_, 8, 2) = 1 == 65536 00000000000000001000000000000000
vec($_, 9, 2) = 1 == 262144 00000000000000000010000000000000
vec($_,10, 2) = 1 == 1048576 00000000000000000000100000000000
vec($_,11, 2) = 1 == 4194304 00000000000000000000001000000000
vec($_,12, 2) = 1 == 16777216 00000000000000000000000010000000
vec($_,13, 2) = 1 == 67108864 00000000000000000000000000100000
vec($_,14, 2) = 1 == 268435456 00000000000000000000000000001000
vec($_,15, 2) = 1 == 1073741824 00000000000000000000000000000010
vec($_, 0, 2) = 2 == 2 01000000000000000000000000000000
vec($_, 1, 2) = 2 == 8 00010000000000000000000000000000
vec($_, 2, 2) = 2 == 32 00000100000000000000000000000000
vec($_, 3, 2) = 2 == 128 00000001000000000000000000000000
vec($_, 4, 2) = 2 == 512 00000000010000000000000000000000
vec($_, 5, 2) = 2 == 2048 00000000000100000000000000000000
vec($_, 6, 2) = 2 == 8192 00000000000001000000000000000000
vec($_, 7, 2) = 2 == 32768 00000000000000010000000000000000
vec($_, 8, 2) = 2 == 131072 00000000000000000100000000000000
vec($_, 9, 2) = 2 == 524288 00000000000000000001000000000000
vec($_,10, 2) = 2 == 2097152 00000000000000000000010000000000
vec($_,11, 2) = 2 == 8388608 00000000000000000000000100000000
vec($_,12, 2) = 2 == 33554432 00000000000000000000000001000000
vec($_,13, 2) = 2 == 134217728 00000000000000000000000000010000
vec($_,14, 2) = 2 == 536870912 00000000000000000000000000000100
vec($_,15, 2) = 2 == 2147483648 00000000000000000000000000000001
vec($_, 0, 4) = 1 == 1 10000000000000000000000000000000
vec($_, 1, 4) = 1 == 16 00001000000000000000000000000000
vec($_, 2, 4) = 1 == 256 00000000100000000000000000000000
vec($_, 3, 4) = 1 == 4096 00000000000010000000000000000000
vec($_, 4, 4) = 1 == 65536 00000000000000001000000000000000
vec($_, 5, 4) = 1 == 1048576 00000000000000000000100000000000
vec($_, 6, 4) = 1 == 16777216 00000000000000000000000010000000
vec($_, 7, 4) = 1 == 268435456 00000000000000000000000000001000
vec($_, 0, 4) = 2 == 2 01000000000000000000000000000000
vec($_, 1, 4) = 2 == 32 00000100000000000000000000000000
vec($_, 2, 4) = 2 == 512 00000000010000000000000000000000
vec($_, 3, 4) = 2 == 8192 00000000000001000000000000000000
vec($_, 4, 4) = 2 == 131072 00000000000000000100000000000000
vec($_, 5, 4) = 2 == 2097152 00000000000000000000010000000000
vec($_, 6, 4) = 2 == 33554432 00000000000000000000000001000000
vec($_, 7, 4) = 2 == 536870912 00000000000000000000000000000100
vec($_, 0, 4) = 4 == 4 00100000000000000000000000000000
vec($_, 1, 4) = 4 == 64 00000010000000000000000000000000
vec($_, 2, 4) = 4 == 1024 00000000001000000000000000000000
vec($_, 3, 4) = 4 == 16384 00000000000000100000000000000000
vec($_, 4, 4) = 4 == 262144 00000000000000000010000000000000
vec($_, 5, 4) = 4 == 4194304 00000000000000000000001000000000
vec($_, 6, 4) = 4 == 67108864 00000000000000000000000000100000
vec($_, 7, 4) = 4 == 1073741824 00000000000000000000000000000010
vec($_, 0, 4) = 8 == 8 00010000000000000000000000000000
vec($_, 1, 4) = 8 == 128 00000001000000000000000000000000
vec($_, 2, 4) = 8 == 2048 00000000000100000000000000000000
vec($_, 3, 4) = 8 == 32768 00000000000000010000000000000000
vec($_, 4, 4) = 8 == 524288 00000000000000000001000000000000
vec($_, 5, 4) = 8 == 8388608 00000000000000000000000100000000
vec($_, 6, 4) = 8 == 134217728 00000000000000000000000000010000
vec($_, 7, 4) = 8 == 2147483648 00000000000000000000000000000001
vec($_, 0, 8) = 1 == 1 10000000000000000000000000000000
vec($_, 1, 8) = 1 == 256 00000000100000000000000000000000
vec($_, 2, 8) = 1 == 65536 00000000000000001000000000000000
vec($_, 3, 8) = 1 == 16777216 00000000000000000000000010000000
vec($_, 0, 8) = 2 == 2 01000000000000000000000000000000
vec($_, 1, 8) = 2 == 512 00000000010000000000000000000000
vec($_, 2, 8) = 2 == 131072 00000000000000000100000000000000
vec($_, 3, 8) = 2 == 33554432 00000000000000000000000001000000
vec($_, 0, 8) = 4 == 4 00100000000000000000000000000000
vec($_, 1, 8) = 4 == 1024 00000000001000000000000000000000
vec($_, 2, 8) = 4 == 262144 00000000000000000010000000000000
vec($_, 3, 8) = 4 == 67108864 00000000000000000000000000100000
vec($_, 0, 8) = 8 == 8 00010000000000000000000000000000
vec($_, 1, 8) = 8 == 2048 00000000000100000000000000000000
vec($_, 2, 8) = 8 == 524288 00000000000000000001000000000000
vec($_, 3, 8) = 8 == 134217728 00000000000000000000000000010000
vec($_, 0, 8) = 16 == 16 00001000000000000000000000000000
vec($_, 1, 8) = 16 == 4096 00000000000010000000000000000000
vec($_, 2, 8) = 16 == 1048576 00000000000000000000100000000000
vec($_, 3, 8) = 16 == 268435456 00000000000000000000000000001000
vec($_, 0, 8) = 32 == 32 00000100000000000000000000000000
vec($_, 1, 8) = 32 == 8192 00000000000001000000000000000000
vec($_, 2, 8) = 32 == 2097152 00000000000000000000010000000000
vec($_, 3, 8) = 32 == 536870912 00000000000000000000000000000100
vec($_, 0, 8) = 64 == 64 00000010000000000000000000000000
vec($_, 1, 8) = 64 == 16384 00000000000000100000000000000000
vec($_, 2, 8) = 64 == 4194304 00000000000000000000001000000000
vec($_, 3, 8) = 64 == 1073741824 00000000000000000000000000000010
vec($_, 0, 8) = 128 == 128 00000001000000000000000000000000
vec($_, 1, 8) = 128 == 32768 00000000000000010000000000000000
vec($_, 2, 8) = 128 == 8388608 00000000000000000000000100000000
vec($_, 3, 8) = 128 == 2147483648 00000000000000000000000000000001
<1848> WRONG!!!
use POSIX ":sys_wait_h";
#...
do {
$kid = waitpid(-1, WNOHANG);
} while $kid > 0;
<1853> WRONG!!!
return unless defined wantarray; # don't bother doing more
my @a = complex_calculation();
return wantarray ? @a : "@a";
<1863>
# wipe out *all* compile-time warnings
BEGIN { $SIG{'__WARN__'} = sub { warn $_[0] if $DOWARN } }
my $foo = 10;
my $foo = 20; # no warning about duplicate my $foo,
# but hey, you asked for it!
# no compile-time or run-time warnings before here
$DOWARN = 1;
<1864> WRONG!!!
# run-time warnings enabled after here
warn "\$foo is alive and $foo!"; # does show up
It is ridiculous to insist on mying them all.
That was my point.
--tom
But the fact that something is described as
sin($x)/cos($x)
without a my declaration, is *not* one of them.
The biggest problem is that it is too hard to find the right
information where you're looking for it, because it's scattered
all over the place.
Wide hex char, indeed!
--tom
What would be so stupid about that question? What would you reply if
someone asked you that question?
> I have never ever had the least problem. I've taught many thousands
> of students, directly.
I'm active in biology/bioinformatics, not software engineering or
computer science: I work with people who often had only the most
elementary classes in Perl, if that at all. My colleagues are not
stupid, they just try to get their work done and use whatever tools at
their disposal (in this case perl and its documentation) to assist
them in that. I have never taught students directly, but I have had to
indirectly teach them when working with them. Maybe they wouldn't have
this problem if they had been properly taught, but that's a what-if
scenario to me.
> I don't believe you.
Are you suggesting I'm lying?? Other people's experiences being
different is not an excuse for discounting them.
Leon
The point of the documentation isn't to supply a number of code fragments,
so newbies can program by just cut-and-pasting.
The examples are code *FRAGMENTS*. Some assembly required. We cannot guess
what the scope of the variables in the code that's cut-and-pasted anyway.
But I guess the general population is dumbing down in at an alarming rate.
Cookbooks need detailed instructions, including pictures, on how to peel
potatoes before boiling them, and newbies can only program by cut and
pasting piecemeal chunks.
Abigail
> Are you suggesting I'm lying??
No. I'm saying that I find it unbelievable. Perhaps
you have a selective memory. Perhaps you are forgetting
things, or remembering others.
But yes, I mainly teach programmers programming.
I don't have a great deal of success with nonprogrammers,
because it's so hard to get then to "get it".
--tom
I consider that an incorrect assertion. It would be correct if you
said "The point of the documentation isn't JUST to supply a number of
code fragments".
I would argue that one of the points of the documents is to do exactly
that. The documentation has other purposes, but one of them is to help
beginners learn to program. I don't think there is any debate on that
as I have seen quotes from Larry basically saying the entire language
was designed to make it easy for beginners to be productive. It seems
to me having a usable set of code fragments is part of that.
> The examples are code *FRAGMENTS*. Some assembly required. We cannot guess
> what the scope of the variables in the code that's cut-and-pasted anyway.
Well, that is not entirely correct. Some /are/ full blown programs.
And IMO as such should use some of what I would consider to be the
less controversial aspects of newer style.
I think maybe there is some dividing line between examples which are
meant to be succinct and demonstrate only one particular thing, and
larger examples which while intended to demonstrate some particular
issue, or whatnot, should probably also be usable by beginners as
building blocks, and be a *solid* foundation for building on - and to
me, that DOES I am afraid mean a different style than Tom's.
I'm thinking here in particular of global filehandles, and lexical
scoped variables.
I respect that Tom sees things differently, but I feel on these two at
least that he is wrong. And the arguments I have seen from him in
regard to justifying his position on these ones isn't to me very
compelling.
> But I guess the general population is dumbing down in at an alarming rate.
Whatever. :-)
If one reads various literature of the past, well, as long as humans
have been writing stuff down there is always someone bemoaning the
dumbing down, the loss of tradition, the loss of manners or whatnot of
the previous generation.
I bet there is a cuneiform tablet out there in some deseret somewhere
basically saying "These upstart kids have no respect and no clue"....
:-)
> Cookbooks need detailed instructions, including pictures, on how to peel
> potatoes before boiling them,
That is more an indictment of the fast-food era than a question of
dumbing down. If the only potato you ever saw in your life came out of
a box, or presliced from the freezer....
> newbies can only program by cut and pasting piecemeal chunks.
I don't buy that. Lots and lots and lots of programmers, including
well known ones, started off by typing example programs into their
computers.
I remember the first programs I wrote when I was a kid were direct
copies from the manuals that came with the Pet computer. They amounted
to small routines that made it look like a ball was bouncing around
the screen. I then learned that I could combine them in interesting
ways, and eventually wrote a game. I never would have gotten there if
the code didnt work as printed in the manual. Later in my career I
have learned several languages by cutting and pasting code snippets
that I found from places to achieve the results I needed - I bet a
LOT of people learn Javascript that way, and learning by trial and
error. I am convinced that of the people on this list besides maybe
yourself, that each one has learned at least one language this way.
Makefiles anyone? HTML Markup maybe? SQL possible? Javascript? Maybe
Python? Maybe even C.
I think the examples, except when very short, or where it would
clearly distract from the intent, *should* be building blocks intended
for beginners to reuse. Everything we can do to expand the usage and
audience of Perl is good for those of us who are professional Perl
programmers - it means we will have a Job for a long time coming. Even
if it is just repairing crappy code. :-) So just think of it this way,
you just might be arguing against something that one day will make
your job a lot easier... ;-)
Lets not forget that the audience for these things may well be
children, they may be professionals with no real programming
knowledge, they may be people whose only knowledge of programming is
Visual Basic for Applications. They wont just be graduated computer
science professionals.
cheers,
> Well, that is not entirely correct. Some /are/ full blown programs.
*Those* I do try to always my() or our() or state() or sometimes
even local(), which is indeed appropriate in places:
use Carp qw< :DEFAULT cluck >;
if (something_or_other) {
local $SIG{__WARN__} = sub { cluck "untrapped warning explanation" };
local $^W = 1;
call_something_else();
}
# local()s pop once that last closing brace is done
It's the isolated snippets like the zillion I last night pointed out in
perlfunc where I feel all the declaration detracts from the point.
If you believe that every possible example in Perl needs to be fully
declared, than by all means do so. But make sure you always start every
snippet with
#!/usr/bin/env perl -CLA
use 5.010;
use utf8;
use strict;
use autodie;
use warnings qw<FATAL all>;
use open qw<IO :utf8 :std>;
END { close STDOUT }
or whatever boilerplate is currently considered
de rigeur by all those trendy mODERN pERL people.
Can you truly argue that that would *help* everything?
* If so, what?
* If not, then what is all the fuss about?
>> But I guess the general population is dumbing down in at an
>> alarming rate.
> Whatever. :-)
I'm with Abigail on this. I was taught not to assume one's
audience is full of idiots. That doesn't mean to be overly
clever, just not talk to down to them.
This is no longer Convention Wisdom. Now you must assume
that nobody has an iota of a clue.
While this may work for certain sorts of presentations, I
believe it is at most approprate only at the initial stage
of language acquisition.
But it seems now that we are expected to treat people like
babies their whole lives long.
Isn't that what the argument really is here?
I feel like there is a certain contingent that holds Perl::Critic as
some sort of holy scripture, golden^Wclay tablets full of Biblical
injunctions that we must all slavishly follow if we are to be good
little perlians and see the good programming medal bestowed upon us.
As you see, I disbelieve. Utterly.
--tom
PS: Yves, you have written more than I have currently processed.
That doesn't mean I agree or disagree, just that I haven't
processed it yet. I may do so later if it really seems
deserving.
That's one thing. The other thing is to copy-and-paste some code fragment
from documentation, slice it into your boilerplate, expect it to work,
and complain if it doesn't.
By all means, I'm not expecting anyone to ignore the documentation.
Copy-and-paste all you want. Just realize you aren't copying entire
programs; whatever fragment you copy will interfere with the rest of
the program.
Note that just putting 'my' everywhere doesn't solve the copy-and-paste
problem. Naively copying such fragments will create variables whose scope
is too limited - and you'll have another set of newbies complaining their
program doesn't work.
Blindly copying fragments into your program without thought is as likely
to create a good working program as expecting to be a good driver after
watching some Formula 1 or NASCAR events, and copying the drivers.
Abigail
I think we would both agree that that is way to much. And I
automatically assume code with "use utf8" in it is subtly broken until
proved otherwise anyway. :-)
In fact I suspect over a pint we would probably mostly agree about
what is too much. :-)
> * If so, what?
>
> * If not, then what is all the fuss about?
Well, we are discussing the location of the "sweet spot of balance"
between the competing demands on our documentation. I was reacting to
what seemed to me to be an extreme positioning of that sweet spot.
>>> But I guess the general population is dumbing down in at an
>>> alarming rate.
>
>> Whatever. :-)
>
> I'm with Abigail on this. I was taught not to assume one's
> audience is full of idiots. That doesn't mean to be overly
> clever, just not talk to down to them.
>
> This is no longer Convention Wisdom. Now you must assume
> that nobody has an iota of a clue.
It is a better default. You can always skip over and ignore things you
know, but its hard to find out about things you have no clue about.
> While this may work for certain sorts of presentations, I
> believe it is at most approprate only at the initial stage
> of language acquisition.
>
> But it seems now that we are expected to treat people like
> babies their whole lives long.
Well thats the thing, you seem to be suggesting that we should treat
people as adults their whole lives long, which also doesn't make
sense.
Newbies aren't hardened veterans of the digital wars like you are. The
point being there are multiple audience for our documentation, we are
unlikely to make all of them happy at once. But again, its easier for
a veteran to ignore something that they know about than it is for a
newbie to find out about something that isn't explicitly noted.
> Isn't that what the argument really is here?
It may have transformed into that, but personally if I wanted a
discussion like that Id bring up politics with my dad.
I think the real argument here is about how accessible the
documentation is to beginners, and what assumptions we make about the
audience for our documentation.
> I feel like there is a certain contingent that holds Perl::Critic as
> some sort of holy scripture, golden^Wclay tablets full of Biblical
> injunctions that we must all slavishly follow if we are to be good
> little perlians and see the good programming medal bestowed upon us.
Well I can assure that PBP is one of the best ways to get a
reactionary comment from me too. But I really dont feel that "the docs
should use my vars, and use lexically scoped filehandles, insofar as
this does not distract from the core point being documented" is
particularly Perl::Critic/PBP related. It is easy, as I think Shlomi
did to go way to far. For instance, *I* think its a good think that
*your* examples use '||' and not 'or' for exception handling. I think
that is useful. However, I dont think any particular advantage is
served by using global vars or global filehandles.
>
> As you see, I disbelieve. Utterly.
Disbelieve what? :-) Oh. I see, you mean the Official Party Line.
Well, that is just because you have not been assimilated yet. But you
will be assimilated. Or maybe exterminated. Depends which tv show you
prefer. ;-)
In all seriousness, I really think the whole PBP/Perl::Critic thing
got way out of hand. Instead of being a sensible tool for looking for
potentially dangerous constructs, or recommendations that increase
code re-use and like, it turned into a sort of holy war.
For instance, I have formed a style that says that assignment should
be no-whitespace-on-left. I formed this style because I often work on
code that mixes SQL and Perl together, (although an early education in
Pascal probably also contributes), and this helps me to distinguish
between an sql "=" and a perl "=", which do not have the same meaning.
So i would do this:
my $sql= "select * from Foo where x = 1";
notice how the two uses of "=" have different whitespacing. PBP
apparently considers this spacing choice to be incorrect. I not so
humbly disagree. :-) So I can see how some of this stuff would annoy
you.
But on the other hand using lexical filehandles IMO means that people
dont fall into the trap of reusing handles. It also means that they
wont leave files open for the duration of the program if they do not
explicitly close it. It also tends to mean that code that formerly
would share a global filehandle now passes around a lexical filehandle
instead. This means its easy to trace process flow and see what does
what.
I think these concerns outweigh any other considerations, and as such
I basically do not use global handles beside STDOUT and friends. And I
think beginners should be strongly encouraged to do the same.
Similar argument for lexical variables.
Pretty much the rest of the things that Shlomi's "fixed" IMO amount to
the same thing as someone not liking the way I use whitespace with
assignment.
That is, something they should get over (if they aren't that smart) or
something they should learn from (if they are smart), even if they
ultimately reject it.
> --tom
>
> PS: Yves, you have written more than I have currently processed.
> That doesn't mean I agree or disagree, just that I haven't
> processed it yet. I may do so later if it really seems
> deserving.
Sure, no worries. :-) Hope you have a good weekend.
I forgot to add the obligatory:
use sigtrap qw< stack-trace normal-signals error-signals >;
>> END { close STDOUT }
>>
>> or whatever boilerplate is currently considered
>> de rigeur by all those trendy mODERN pERL people.
>>
>> Can you truly argue that that would *help* everything?
> I think we would both agree that that is way to much. And I
> automatically assume code with "use utf8" in it is subtly
> broken until proved otherwise anyway. :-)
Oh drat! That's distressing. I some time ago reached the conclusion
that C<use encoding> was evil, but if you are now telling me that
use utf8 is just as bad, I don't know *what* I'm going to do!
One potential problem area that I can imagine is the same one you get with
XML's inline charset declaration: it has to a proper superset of ASCII,
and no non-ASCII characters may occur before the charset declaration.
Is it that you're worried people will think they will get all their strings
magically _utf8_on()d that way -- when in fact, they don't and the same
rules are followed as without the pragma?
Or do you fear it's old code that thought that was the only way to get
Unicode semantics, which is almost certainly wrong in many other ways, too?
Or are you worried about non-shortest-form UTF-8 illegalities
sneaking in unchecked?
I have a feeling that there must be something more than those, because
they're all obvious and I figure you wouldn't have mentioned it if there
weren't something more perilous and more insidious.
And *that* has got me nervous.
> In fact I suspect over a pint we would probably mostly agree
> about what is too much. :-)
Prolly. Colorado is the state with the most microbreweries per
capita. I don't much care for the beer in Europe apart from what
you get in the British Isles and in Belgium (maybe Benelux).
The rest of it is too easily forgotten, though now and then some
beers from Germany pleasantly surprise me; just not the rule.
> Sure, no worries. :-) Hope you have a good weekend.
That will take some doing. I'm supposed to working on
the Camel's regex chapter. But I'm also supposed to
wrestling with Junit test cases whose results are due Monday morning
on an already extended deadline for an academic paper submission.
So far, I have already:
* transparently rewritten all Java regexes out from
under it so they actually work (our text is all UTF-8).
* written Perl code to write a thousand Java Junit test
cases because the framework is too stupid to behave
properly.
* taken to writing my Java with cpp frontending it so I
can have assert macros showing the real unevaluated
expression as a string, and so I can do things like:
#ifdef FIX_BUGGY_JAVA_REGEXES
import static tchrist.PatternUtils.unicode_charclass;
# define FIX(BROKEN) unicode_charclass(BROKEN)
#else
# define FIX(BROKEN)
#endif
leading to code like:
Matcher m = Pattern.compile(FIX(regex)).matcher(string);
The Java monoglots are completely appalled. One "helpfully" gave me almost
five pages of supernasty Java code just to get around what I did in a few
lines with cpp and token-catenation to effectively pass function pointers.
I politely declined.
Fortunately the only success metric at work is getting the job done, not
purity of soul. I *always* beat the Java people in time-to-solution, even
when I use Java, but that's because per their viewpoint, I "cheat".
Whatever. (Wonder whether Rob Pike's hiring for Go? :()
So it may not be a good weekend. I'll try to take some time away
from the computer. That should help.
--tom
I dont know that I would say that. On the other hand I think sticking
to ASCII, or other approaches might make life simpler.
> One potential problem area that I can imagine is the same one you get with
> XML's inline charset declaration: it has to a proper superset of ASCII,
> and no non-ASCII characters may occur before the charset declaration.
>
> Is it that you're worried people will think they will get all their strings
> magically _utf8_on()d that way -- when in fact, they don't and the same
> rules are followed as without the pragma?
>
> Or do you fear it's old code that thought that was the only way to get
> Unicode semantics, which is almost certainly wrong in many other ways, too?
>
> Or are you worried about non-shortest-form UTF-8 illegalities
> sneaking in unchecked?
>
> I have a feeling that there must be something more than those, because
> they're all obvious and I figure you wouldn't have mentioned it if there
> weren't something more perilous and more insidious.
>
> And *that* has got me nervous.
Its them all together. Ive seen too much code that used utf8
improperly to trust it.
>> In fact I suspect over a pint we would probably mostly agree
>> about what is too much. :-)
>
> Prolly. Colorado is the state with the most microbreweries per
> capita. I don't much care for the beer in Europe apart from what
> you get in the British Isles and in Belgium (maybe Benelux).
> The rest of it is too easily forgotten, though now and then some
> beers from Germany pleasantly surprise me; just not the rule.
I generally drink Guiness. :-)
[...]
> The Java monoglots are completely appalled. One "helpfully" gave me almost
> five pages of supernasty Java code just to get around what I did in a few
> lines with cpp and token-catenation to effectively pass function pointers.
>
> I politely declined.
>
> Fortunately the only success metric at work is getting the job done, not
> purity of soul. I *always* beat the Java people in time-to-solution, even
> when I use Java, but that's because per their viewpoint, I "cheat".
Yeah. I understand. I have had similar experiences with mixing cpp and sql code.
> Whatever. (Wonder whether Rob Pike's hiring for Go? :()
>
> So it may not be a good weekend. I'll try to take some time away
> from the computer. That should help.
Indeed. Time in the big room always helps.
This thread is really depressing. Personally, I like all of Shlomi's
suggestions. I can't fathom why bareword global filehandles are still
pervasive in the perl docs. But instead of the community getting to
discuss the merits of the changes and then have some kind of vote, one
maintainer with a big ego can just say, "VETO VETO VETO ... my docs
are already perfect!" Is that how things work in the perl community?
What incentive would I or Shlomi or anyone else have to spend their
time to try to improve the docs if this is how things work.
I'm depressed that people are telling me that I don't talk good no more.
That there is something about my language that isn't safe for the precious
children to hear. That there are things one isn't supposed to do--not that
they're illegal or anything, just that they're "adults-only" topics.
Deleting things from Perl that you've decided make you wrinkle your nose
has always been a a *very* popular idea historically. It's also been
fairly effective at killing off interest in helping develop Perl, because
every new generation find that they disapprove of the one that came before
them, so they'd like to hurry them off to the grave before anybody notices.
If you want to remove something from the language, then bring it up with
with on the discussion list as something you want do see killed in the
language. But don't try to ram your idea of moral rectitude down the rest
of our throats by these stealth edits of the documentation to better align
with the Holy Scriptures of the Supreme Sacred Congregation of the Roman
and Universal Inquisition.
Surely driving away a few people who aren't family friendly is worth the
vast strides of progress you promise to lead those of us who survive into.
I think it's a stupidly harmful thing to do, and I think it is contrary to
the spirit of Perl. But what do I know? I'm pretty sure only wrong-thinking
people think like I do, and we must be pushed aside for the brave new world
you seek to bring about. Go ahead, push a little: I don't mind jumping.
It'd save me a lot of grief, and save you even more. The good of the many...
--tom
I don't think anyone said any such thing, I sure don't think that. I
can imagine it feels like that, since this discussion is about what
many perceive to be wrong about those documents, not on what is good
about them.
> Deleting things from Perl that you've decided make you wrinkle your nose
> has always been a a *very* popular idea historically. It's also been
> fairly effective at killing off interest in helping develop Perl, because
> every new generation find that they disapprove of the one that came before
> them, so they'd like to hurry them off to the grave before anybody notices.
Not deleting anything can be just as effective at killing off interest
in helping develop Perl. It's all about balance.
> Surely driving away a few people who aren't family friendly is worth the
> vast strides of progress you promise to lead those of us who survive into.
Maybe they are driving you away, but you're driving other people away
the same way. If I may speak for myself, I find this whole discussion
extremely discouraging. If anything, this discussion is far more
heated and far more dominated by emotion on all sides than it should
be.
Leon
People are saying the perlipc docs are Unix centric, which they probably
are. Adding some paragraphs and examples how to do IPC on VMS and Windows
is probably a much better way to improve the documentation than insisting
bare file handles aren't used, or claiming 'or' is somehow better than '||'.
There's a lot of the documentation that can be improved; it's badly
organized [*], things are hard to find [*], incorrectly documented [*],
it's missing lots of examples, and it's probably too Unix centric [+].
I think we have a long way to go before the most constructive thing that
can be done with documentation is twiddling with the coding style of
examples.
[*] If I ever have a couple of spare months, I want to rewrite the
thingserlre documentation.
[+] Probably strongly influenced by the fact the majority of perl and
Perl documentation authors are native Unixians.
Abigail
I think there is a difference in modifying someone elses
documentation, and writing a totally new doc. I also think there is a
big difference between patches to code which fix bugs or add
functionality, and patches to documentation that is not actually
wrong, but instead of a style no longer in fashion. To me it is a bit
like suggesting that Shakespeare needs to be "modernized" because of
the archaic English he used.
However, if you, or Shlomi think you can write a better perlipc.pod
from scratch, then you should do so, or any other doc.
If we think it is qualitatively superior then we would probably
replace the existing version.
More likely we would end up with two docs. And the community would be
richer for it.
So I think we are right in respecting a given documents artistic
rights to have their vision presented as they wished, within reason.
We can always decide not to use the doc at all if we feel they are
being unreasonable. I doubt you would get a consensus for such an
extreme action amongst the committers though. I think we generally
dont feel as strongly about these changes as you seem to. Although I
respect your reasons for doing so.
> Is that how things work in the perl community?
Sometimes yes. We have a long tradition of accepting there is a role
for a "benevolent dictator" in our community, as without one, we all
too easily descend into long tedius arguments that get us nowhere.
Like this one has verged upon. (I think Abigails suggested "example
caveat" is a productive step that means we have not /quite/ verged
into the total waste of time category.)
> What incentive would I or Shlomi or anyone else have to spend their
> time to try to improve the docs if this is how things work.
We all have different incentives. I would hope that you dont feel that
a predicate on your contributing is the right to change anything you
wish however you wish. That is not how it works. No matter how much I
wish it did sometimes.
I hope you stay positive about contributing to perl, and find other
subjects where you can do so. We have a lot more to look into than
Tom's docs.
On Sunday 05 December 2010 18:43:44 Abigail wrote:
> On Sun, Dec 05, 2010 at 01:54:29AM -0500, Naveed Massjouni wrote:
> > This thread is really depressing. Personally, I like all of Shlomi's
> > suggestions. I can't fathom why bareword global filehandles are still
> > pervasive in the perl docs. But instead of the community getting to
> > discuss the merits of the changes and then have some kind of vote, one
> > maintainer with a big ego can just say, "VETO VETO VETO ... my docs
> > are already perfect!" Is that how things work in the perl community?
> > What incentive would I or Shlomi or anyone else have to spend their
> > time to try to improve the docs if this is how things work.
>
> People are saying the perlipc docs are Unix centric, which they probably
> are. Adding some paragraphs and examples how to do IPC on VMS and Windows
> is probably a much better way to improve the documentation than insisting
> bare file handles aren't used, or claiming 'or' is somehow better than
> '||'.
>
> There's a lot of the documentation that can be improved; it's badly
> organized [*], things are hard to find [*], incorrectly documented [*],
> it's missing lots of examples, and it's probably too Unix centric [+].
> I think we have a long way to go before the most constructive thing that
> can be done with documentation is twiddling with the coding style of
> examples.
I agree that there are many aspects where the documentation could use some
improvements. However, if I (or someone else) step forward and offer to
volunteer my time in changing one of the *.pod files in a certain aspect, then
either my suggestion is an improvement or it detracts from the value of the
documentation. If my suggestion is indeed an improvement (no matter how
small), then I believe that my suggestion for modification should be approved,
which will allow me to work on the patch with bigger confidence that it will
eventually be applied and thus improve the overall state of the documentation.
Or to use the common proverb "One bird in the hand is better than two in the
bush." (or "One bird in the hand is better than ten in the tree." as the Arabs
say.).
Now I think that some of my style/best-practices suggestions are an
improvement and I'd like to pursue them. I also think that we should show how
to write the sockets' code using IO::Socket and friends rather than using the
lower-level API calls, which are no longer recommended (and have not been for
years). May I pursue that?
Regards,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
First stop for Perl beginners - http://perl-begin.org/
And I'm strongly against that sentiment.
I really do think p5p, and hence the documentation, should *not* have a
style preference, or have some form of "best practice" (nor do I believe
you'll find consensus on what "best practice" will be). Style guides,
coding standards, best practices, or whatever you want to label it only
gives rise to coding police, and it's only fuel to people who only answer
questions on usenet or Perlmonks with "well, for starters following these
as these rules", regardless whether that helps answering the question
or not.
Pursue all you want. Just expect feedback which may not agree with you.
Abigail
Aren't you describing territoriality here?
* http://en.wikipedia.org/wiki/Territoriality_%28nonverbal_communication%29
* http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-
bazaar/ar01s11.html
(sorry for the second broken link).
I'm in no position to write my own perlipc.pod from scratch - I'd rather build
on the efforts of tchrist and other contributors. And as Aristotle noted we
don't need another document with the same purpose. And I'd like contributors
to discuss changes to the documentation that they originated based on their
merit and not "veto" them, just because they are territorial about their
documentation. This is also because the documentation affects and reflects on
the collective community of developers and users, and we are all held
responsible for it.
> > What incentive would I or Shlomi or anyone else have to spend their
> > time to try to improve the docs if this is how things work.
>
> We all have different incentives. I would hope that you dont feel that
> a predicate on your contributing is the right to change anything you
> wish however you wish. That is not how it works. No matter how much I
> wish it did sometimes.
>
> I hope you stay positive about contributing to perl, and find other
> subjects where you can do so. We have a lot more to look into than
> Tom's docs.
The way I see it what happened was that I wrote an email with aspects of
perlipc.pod that I found lacking, and not idiomatic up to recent best
practices, thcrist replying that he doesn't like any of the changes and
VETOing them (without saying why the status quo was better, just by giving
other irrelevant reasons), and some other people discussing why they thought
what I or other people said had a relative merit and should be implemented
(althugh possibly, like Abigail said, not at the utmost priority). I didn't
even start patching perlipc yet (at least not after tchrist's rewrite of its
original version which forced me to restart my work.).
I also think that the Perl 5 documentation *should* reflect the agreed best
practices (and I don't necessarily mean Damian's PBP). We had lexical
filehandles since at least perl-5.6.x and everyone agrees that they are a best
practice, and "use strict;" is also a good idea, and we encourage everybody to
do "use warnings;" instead of "-w". Therefore, we should practice what we
preach, and make sure that the core docs don't unnecessarily demonstrate
paradigms that have been agreed to be bad for years.
Regards,
Shlomi Fish
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
My Public Domain Photos - http://www.flickr.com/photos/shlomif/
Both of those are falsely stated. First, your notion of irrelevance is
mere opinion. Second, I had previously explained my reasoning in full,
and so saw no need of pasting the same redundant explanation at each point
as some aide-mémoire for those of short attention spans.
> I also think that the Perl 5 documentation *should* reflect
> the agreed best practices (and I don't necessarily mean
> Damian's PBP).
You bend that word "agreed" into something it does not mean.
When--and only when--you've worked your way down this list
far enough that you've finally reached my stuff, do give me a holler.
# 1 STRICT 0% success 368 runs = 0 passed + 368 failed < pod/perlapi.pod
# 2 Warnings 7% success 368 runs = 24 passed + 344 failed < pod/perlapi.pod
# 3 STRICT 33% success 275 runs = 90 passed + 185 failed < pod/perlfunc.pod
# 4 STRICT 18% success 200 runs = 37 passed + 163 failed < pod/perlfaq4.pod
# 5 Warnings 49% success 275 runs = 136 passed + 139 failed < pod/perlfunc.pod
# 6 STRICT 12% success 148 runs = 18 passed + 130 failed < dist/Math-BigInt/lib/Math/BigInt.pm
# 7 STRICT 12% success 148 runs = 18 passed + 130 failed < lib/Math/BigInt.pm
# 8 Warnings 36% success 200 runs = 72 passed + 128 failed < pod/perlfaq4.pod
# 9 STRICT 29% success 150 runs = 44 passed + 106 failed < cpan/CGI/lib/CGI.pm
# 10 STRICT 29% success 150 runs = 44 passed + 106 failed < lib/CGI.pm
# 11 Warnings 29% success 148 runs = 43 passed + 105 failed < dist/Math-BigInt/lib/Math/BigInt.pm
# 12 Warnings 29% success 148 runs = 43 passed + 105 failed < lib/Math/BigInt.pm
# 13 STRICT 3% success 98 runs = 3 passed + 95 failed < pod/perlguts.pod
# 14 Warnings 4% success 98 runs = 4 passed + 94 failed < pod/perlguts.pod
# 15 STRICT 35% success 141 runs = 49 passed + 92 failed < pod/perlretut.pod
# 16 Warnings 42% success 150 runs = 63 passed + 87 failed < cpan/CGI/lib/CGI.pm
# 17 Warnings 42% success 150 runs = 63 passed + 87 failed < lib/CGI.pm
# 18 STRICT 37% success 126 runs = 47 passed + 79 failed < pod/perlop.pod
# 19 normal 79% success 368 runs = 290 passed + 78 failed < pod/perlapi.pod
# 20 STRICT 4% success 80 runs = 3 passed + 77 failed < pod/perlxs.pod
# 21 STRICT 24% success 99 runs = 24 passed + 75 failed < pod/perlfaq5.pod
# 22 Warnings 8% success 80 runs = 6 passed + 74 failed < pod/perlxs.pod
# 23 STRICT 8% success 78 runs = 6 passed + 72 failed < ext/POSIX/lib/POSIX.pod
# 24 STRICT 8% success 78 runs = 6 passed + 72 failed < lib/POSIX.pod
# 25 STRICT 5% success 75 runs = 4 passed + 71 failed < cpan/Test-Simple/lib/Test/Builder.pm
# 26 STRICT 5% success 75 runs = 4 passed + 71 failed < lib/Test/Builder.pm
# 27 STRICT 16% success 83 runs = 13 passed + 70 failed < pod/perltrap.pod
# 28 Warnings 11% success 75 runs = 8 passed + 67 failed < cpan/Test-Simple/lib/Test/Builder.pm
# 29 Warnings 11% success 75 runs = 8 passed + 67 failed < lib/Test/Builder.pm
# 30 Warnings 14% success 78 runs = 11 passed + 67 failed < ext/POSIX/lib/POSIX.pod
# 31 Warnings 14% success 78 runs = 11 passed + 67 failed < lib/POSIX.pod
# 32 STRICT 0% success 65 runs = 0 passed + 65 failed < cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Any.pm
# 33 STRICT 0% success 65 runs = 0 passed + 65 failed < lib/ExtUtils/MM_Any.pm
# 34 Warnings 2% success 65 runs = 1 passed + 64 failed < cpan/ExtUtils-MakeMaker/lib/ExtUtils/MM_Any.pm
# 35 Warnings 2% success 65 runs = 1 passed + 64 failed < lib/ExtUtils/MM_Any.pm
# 36 normal 21% success 80 runs = 17 passed + 63 failed < pod/perlxs.pod
# 37 STRICT 18% success 76 runs = 14 passed + 62 failed < cpan/Test-Simple/lib/Test/More.pm
# 38 STRICT 18% success 76 runs = 14 passed + 62 failed < lib/Test/More.pm
# 39 Warnings 51% success 126 runs = 64 passed + 62 failed < pod/perlop.pod
# 40 STRICT 21% success 76 runs = 16 passed + 60 failed < pod/perlpacktut.pod
# 41 STRICT 15% success 68 runs = 10 passed + 58 failed < pod/perldiag.pod
# 42 Warnings 24% success 76 runs = 18 passed + 58 failed < cpan/Test-Simple/lib/Test/More.pm
# 43 Warnings 24% success 76 runs = 18 passed + 58 failed < lib/Test/More.pm
# 44 STRICT 0% success 56 runs = 0 passed + 56 failed < cpan/Test-Harness/lib/TAP/Parser.pm
# 45 STRICT 0% success 56 runs = 0 passed + 56 failed < lib/TAP/Parser.pm
# 46 STRICT 17% success 66 runs = 11 passed + 55 failed < pod/perlhack.pod
# 47 STRICT 35% success 84 runs = 29 passed + 55 failed < pod/perlsub.pod
# 48 Warnings 18% success 66 runs = 12 passed + 54 failed < pod/perlhack.pod
# 49 Warnings 46% success 99 runs = 46 passed + 53 failed < pod/perlfaq5.pod
# 50 normal 48% success 98 runs = 47 passed + 51 failed < pod/perlguts.pod
# 51 Warnings 65% success 141 runs = 92 passed + 49 failed < pod/perlretut.pod
# 52 normal 26% success 66 runs = 17 passed + 49 failed < pod/perlhack.pod
# 53 Warnings 29% success 68 runs = 20 passed + 48 failed < pod/perldiag.pod
# 54 Warnings 43% success 84 runs = 36 passed + 48 failed < pod/perlsub.pod
# 55 Warnings 38% success 76 runs = 29 passed + 47 failed < pod/perlpacktut.pod
# 56 STRICT 8% success 50 runs = 4 passed + 46 failed < pod/perldata.pod
# 57 STRICT 37% success 73 runs = 27 passed + 46 failed < pod/perlfaq8.pod
# 58 Warnings 21% success 56 runs = 12 passed + 44 failed < cpan/Test-Harness/lib/TAP/Parser.pm
# 59 Warnings 21% success 56 runs = 12 passed + 44 failed < lib/TAP/Parser.pm
# 60 Warnings 47% success 83 runs = 39 passed + 44 failed < pod/perltrap.pod
# 61 STRICT 7% success 46 runs = 3 passed + 43 failed < cpan/File-Temp/Temp.pm
# 62 STRICT 7% success 46 runs = 3 passed + 43 failed < lib/File/Temp.pm
# 63 STRICT 22% success 55 runs = 12 passed + 43 failed < pod/perlfaq7.pod
# 64 STRICT 32% success 63 runs = 20 passed + 43 failed < pod/perlopentut.pod
# 65 STRICT 5% success 44 runs = 2 passed + 42 failed < cpan/Pod-Parser/lib/Pod/Parser.pm
# 66 STRICT 5% success 44 runs = 2 passed + 42 failed < lib/Pod/Parser.pm
# 67 STRICT 34% success 62 runs = 21 passed + 41 failed < pod/perltoot.pod
# 68 Warnings 7% success 44 runs = 3 passed + 41 failed < cpan/Pod-Parser/lib/Pod/Parser.pm
# 69 Warnings 7% success 44 runs = 3 passed + 41 failed < lib/Pod/Parser.pm
# 70 STRICT 9% success 44 runs = 4 passed + 40 failed < lib/Text/Balanced.pm
# 71 STRICT 11% success 45 runs = 5 passed + 40 failed < pod/perlref.pod
# 72 STRICT 2% success 40 runs = 1 passed + 39 failed < pod/perlintern.pod
# 73 STRICT 9% success 43 runs = 4 passed + 39 failed < cpan/Text-Balanced/lib/Text/Balanced.pm
# 74 STRICT 32% success 56 runs = 18 passed + 38 failed < pod/perlcall.pod
# 75 Warnings 5% success 40 runs = 2 passed + 38 failed < pod/perlintern.pod
# 76 Warnings 14% success 44 runs = 6 passed + 38 failed < lib/Text/Balanced.pm
# 77 Warnings 17% success 46 runs = 8 passed + 38 failed < cpan/File-Temp/Temp.pm
# 78 Warnings 17% success 46 runs = 8 passed + 38 failed < lib/File/Temp.pm
# 79 STRICT 3% success 38 runs = 1 passed + 37 failed < dist/Locale-Maketext/lib/Locale/Maketext.pod
# 80 STRICT 3% success 38 runs = 1 passed + 37 failed < lib/Locale/Maketext.pod
# 81 STRICT 12% success 42 runs = 5 passed + 37 failed < pod/perliol.pod
# 82 Warnings 12% success 42 runs = 5 passed + 37 failed < pod/perliol.pod
# 83 Warnings 14% success 43 runs = 6 passed + 37 failed < cpan/Text-Balanced/lib/Text/Balanced.pm
# 84 Warnings 26% success 50 runs = 13 passed + 37 failed < pod/perldata.pod
# 85 Warnings 49% success 73 runs = 36 passed + 37 failed < pod/perlfaq8.pod
# 86 STRICT 27% success 48 runs = 13 passed + 35 failed < pod/perlebcdic.pod
# 87 STRICT 41% success 59 runs = 24 passed + 35 failed < pod/perlipc.pod
....
# 214 Warnings 64% success 59 runs = 38 passed + 21 failed < pod/perlipc.pod
....
#1026 normal 93% success 59 runs = 55 passed + 4 failed < pod/perlipc.pod
This witch-hunt is counter-productive and harmful. You should not
be offended, or even surprised, if its results are not agreed to.
Again I urge you to look first to the beam in your own eye before
worrying about the speck in your brother's. Just because it's old
advice doesn't make it lose one scintilla of its applicability.
--tom
Tom, using terms like "witch-hunt" is not fair - it implies there is
malice intent on Shlomi's behalf which I don't think there is any
evidence for. Saying stuff like that is at least as harmful to our
community as you feel their efforts are, and judging by some of the
comments possibly more so.
I respect your right to preserve your doc's style. But if you
contribute to a public project then you should not be offended, or
even surprised, if people argue that it should be patched in ways
which are disagreeable to you.
I don't know. I'm not even sure that my view is rational or self consistent.
I do know that I feel there is some important qualitative difference
between modifying code, and modifying a stand alone document like
perlipc.
> I'm in no position to write my own perlipc.pod from scratch - I'd rather build
> on the efforts of tchrist and other contributors. And as Aristotle noted we
> don't need another document with the same purpose. And I'd like contributors
> to discuss changes to the documentation that they originated based on their
> merit and not "veto" them, just because they are territorial about their
> documentation. This is also because the documentation affects and reflects on
> the collective community of developers and users, and we are all held
> responsible for it.
Again, I am not sure I agree.
I dont feel that *all* of Toms rejections of your changes *are* due to
territoriality, although I suspect a few of them might be, and that
his general tone suggests he does feel that way.
On the other hand I just don't agree with you on some of them.
For instance using || instead of or. I prefer the latter, like you I
believe, however I actually think in some important respects the other
style is better.
If you ONLY ever use || and always use parens on function calls then
you will never get bitten by weird precedence problems like this:
return $foo or $bar;
which I see in code more often than I would prefer. Now, like I said,
I actually prefer 'or' style, with no parens. But I also know all the
places where that can bite you, because I've been bitten. :-) Now you
want Tom to change to a style that is objectively inferior in at least
one or two ways. You haven't really demonstrated to me that you
understand why he prefers his style, or demonstrated to me that you
have a cogent argument for using the 'or' form beyond aesthetics.
Now on some things I agree. But enough I don't agree with, or think
its a dicey argument, that I think Toms opinions should be given extra
consideration when we discuss them.
Again I think you go a bit too far here. I do agree with the sentiment tho.
Well, I don't frequent either Usenet or Perlmonks, but let me answer. (For the
record, I help a lot on IRC and on mailing lists.) I've collected a longish
list of bad practices to avoid (from PBP and other sources) here:
http://perl-begin.org/tutorials/bad-elements/
Now, I've specifically tried to make it as non-controversial as possible and
avoided recommendations that are a matter of taste, and can be done this way
or another.
If you think all style guide / best practices / etc. are not helpful, will you
accept code that:
1. Lacks all indentation?
2. Has magic numbers such as:
my $n = uc($_[3]);
?
3. Has comments or even identifiers in a non-English language?
4. Has duplicate code?
5. Has inconsistent tabs and spaces and looks differently aligned on many tab
widths?
6. Has non-descriptive variable names? Reportedly
http://en.wikipedia.org/wiki/Daniel_J._Bernstein uses many single-letter and
double-letter identifiers in his code.
---------------------
I know none of these will be acceptible to me, because they are not a matter
of taste, but rather objective measures of the internal quality of the code.
However, there are a lot of style debates, like which indentation style to
use, or whether to do my ($self, $args) = @_; or my ($self, %args) = @_; or
whether one should avoid using "unless" instead of of "if (!)" altogether
(which I do), or whether one should avoid trailing conditionals (which I also
avoid), etc. etc. These are still a matter of preference and mostly amoral,
and are not covered in my document.
Now the question is which category making the code strict-safe or using
lexical filehandles belongs to. People have given good arguments for both of
these for many years now, so I think they belong in the things that p5p will
necessitate in code examples (unless someone has a compelling argument why
they are not a good idea).
Regards,
Shlomi Fish
>
> Pursue all you want. Just expect feedback which may not agree with you.
>
>
>
> Abigail
--
-----------------------------------------------------------------
Shlomi Fish http://www.shlomifish.org/
Rethinking CPAN - http://shlom.in/rethinking-cpan
Unlikely.
>
> 2. Has magic numbers such as:
>
> my $n = uc($_[3]);
Depends on the usage. I don't have much problems with:
$minutes = 60 * $hours;
And for manual pages, due to line-length restrictions, I rather accept
a numeric literal, than a descriptive name that causes the line to wrap
on my terminal.
> 3. Has comments or even identifiers in a non-English language?
Depends on the environment.
> 4. Has duplicate code?
Maybe. I do copy-and-paste at $WORK every now and then. Sometimes, the cost
of copying is less than the cost of abstracting. It's a trade-off.
For documentation, I'm even more willing to accept duplicate code.
> 5. Has inconsistent tabs and spaces and looks differently aligned on many tab
> widths?
Personally, I never use tabs, unless the syntax demands it (like Makefiles).
> 6. Has non-descriptive variable names? Reportedly
> http://en.wikipedia.org/wiki/Daniel_J._Bernstein uses many single-letter and
> double-letter identifiers in his code.
Certainly. $i, $n, etc, I use often. For documentation, $foo, $bar, and
friends are often acceptable.
But avoiding really bad techniques is a far cry from enforcing a certain
style. Rejecting code that lacks all indentation isn't the same as changing
identation in existing documentation to what someone considers the optimal
indentation width.
To go back to your suggestions that started this long thread, I don't think
any of the proposals fell into your points 1-6.
> I know none of these will be acceptible to me, because they are not a matter
> of taste, but rather objective measures of the internal quality of the code.
>
> However, there are a lot of style debates, like which indentation style to
> use, or whether to do my ($self, $args) = @_; or my ($self, %args) = @_; or
> whether one should avoid using "unless" instead of of "if (!)" altogether
> (which I do), or whether one should avoid trailing conditionals (which I also
> avoid), etc. etc. These are still a matter of preference and mostly amoral,
> and are not covered in my document.
>
> Now the question is which category making the code strict-safe or using
> lexical filehandles belongs to. People have given good arguments for both of
> these for many years now, so I think they belong in the things that p5p will
> necessitate in code examples (unless someone has a compelling argument why
> they are not a good idea).
Note that lexical filehandles have been possible since October 1994, with
the release of Perl 5.000. It wasn't until the release of 5.6.0 with
the introduction of autovivifying that people actually started using them -
before then, the extra line of code required apparently didn't offset the
benefits. I refuse to believe people wrote bad code for a dozen years
(counting pre-perl5 as well).
Do we have to document autovivifying file handles? Certainly. Do we have
to show how to use lexical filehandles? Yes. Do we have to label code that
uses bare file handles as bad, unwanted or outdated? No.
As for strictness, let me reiterate my opinion. The majority of the examples
of the documentation are code fragments. For brevity reasons, it doesn't
state "use strict;" or "use warnings;". Nor does it declare a package, or
starts with a she-bang line. Often, it doesn't read any data, nor writes
any output. That's all assumed to be "somewhere". Just as declaring used
variables with 'my'. After all, if someone wants to copy lines into his
program, only he knows where scopes end or begin.
Now, if you have some examples where symbolic references are used (and the
examples aren't about symbolic references themselves), you're less likely
to get opposition from me if you propose a patch to either eliminate the
symbolic reference, or a line that points out a symbolic reference is used.
But just blindly slapping 'my' everywhere isn't something that gets me
cheering.
Abigail