Perl Peeves

T

Tim McDaniel

Consider giving up idea that C<+> is "unary plus". It's not. It's a
special that hints B<perl> that's an expression that comes next.
C<perldoc -f map> has more.

That calls it 'a unary "+"'.

Thank you for the pointer. Looking at the examples, I don't see how
Perl decides BLOCK versus EXPR based on changes inside {...}, but
- it gives me a notion of when unary + is useful
- it gives me something to twiddle if Perl misparses a map or grep
that I try to run
 
U

Uri Guttman

AD> Then write (the perlish way)

AD> my $output_value = CONDITION || '0';

that is a poor choice of a false value. sure it works but 0 (no quotes)
or '' would be better. they are more common (perl uses them itself) and
should be trivially faster as '0' would require more work to test for
falsehood.

AD> You were talking about one specific case, which can be addressed. As
AD> for output

AD> $my_boolean=

AD> is illustrative to me. (Unless it might be a ' ')

' ' is a true value. it would be foolish to ever use it as just a
boolean if you want to print it.

uri
 
T

Tad J McClellan

Note that this code does not do the same thing as the code quoted above.

The code quoted above normalizes true values to 1 and false values to 0.

This code only normalizes false values to '0', leaving true values
in their original form.

--------------------
#!/usr/bin/perl
use warnings;
use strict;

use constant CONDITION => 'a true value';
#use constant CONDITION => ''; # a false value

my $output_value = CONDITION || '0';
print "$output_value\n";
 
P

Peter J. Holzer

[ '' in string context, 0 in numeric context ]
That special false is evaluated to blah-blah-blah *immediately* since
the context is known at compile time (am I right?).

No. Consider:

#!/usr/bin/perl
use warnings;
use strict;

my $bool = (1 < 0);

if (rand() < 0.5) {
print "<$bool>\n";
} else {
print 0 + $bool, "\n";
}

hp
 
P

Peter J. Holzer

JE> Yeah, you got a point. Feel free to submit a patch.

perl derived its -rwx ops from the original unix file modes. this was
way before any system that perl was on had ACL's. there is no easy way
to retrofit acl's onto such a simple API.

Semantically that would be quite simple. The question "can this process
with its current priviles read/write/execute this file?" can always be
answered given the file's ACL and the process's privileges. But it may
be impossible to implement:

1) access(2) doesn't do what one might think it does.

2) So it has to be done "manually": Get the ACL, get the current
privileges, compute the result - this means duplicating OS in an
application, and you will almost certainly get get some detail wrong.

3) You may not even have access to the "real" ACL: A filesystem exported
over some network filesystem protocol may have no way to convey the
exact ACL - but it will probably still enforce it's rules.

In conclusion the only way to be sure whether you can read, write or
execute a file is to try it. Reading and writing (non-destructively) is
trivial for regular files, but executing isn't (you may not want to
execute "/usr/local/bin/delete_all_my_data" just to find out whether it
is executable), for directories read and execute are simple, but write
is impossible (you would have to create a file in it).
 
E

Eric Pozharski

Yes. Contrary to what some people apparently believe, it really isn't
one of Perl's strengths that working code can look like modem line noise.

(imho) That "modem line noise" is spice for me.
 
E

Eric Pozharski

[ '' in string context, 0 in numeric context ]
That special false is evaluated to blah-blah-blah *immediately* since
the context is known at compile time (am I right?).

No. Consider:

#!/usr/bin/perl
use warnings;
use strict;

my $bool = (1 < 0);

if (rand() < 0.5) {
print "<$bool>\n";
} else {
print 0 + $bool, "\n";
}

No, special false is sticky. That explains better though, I think.

perl -wle '
my($nil, $empty) = (0, q||);
print qq|<$nil> <$empty>|;
print 0 + $nil;
print 0 + $empty;
'
<0> <>
0
Argument "" isn't numeric in addition (+) at -e line 5.
0

p.s. IOW -- me wrongs.
 
B

Bruce Cook

Peter said:
[ '' in string context, 0 in numeric context ]
That special false is evaluated to blah-blah-blah *immediately* since
the context is known at compile time (am I right?).

No. Consider:

#!/usr/bin/perl
use warnings;
use strict;

my $bool = (1 < 0);

if (rand() < 0.5) {
print "<$bool>\n";
} else {
print 0 + $bool, "\n";
}

Anyone who applies a numeric operator to a logical value and expects
consistent results is asking for trouble. In strongly-typed languages you
would get a compiler or run-time error/warning, however perl is a scripting
language and is built to be flexible, assumes you know what you're doing and
will silently oblige even the most horrendous abuses.

You actually have the same issue in C: false is defined as 0 and true is
!false. I have seen a discussion recently where someone was using an
library "elegantly" and came unstuck on a different platform because he
assumed that the true returned from that library was 1 (as it was on his
development platform). His usage became really interesting because the new
platform was returning -1 (binary all 1s), which is another common value
used for true.

As a programmer you need to understand when you're crossing type boundaries
and make sure at that point you force defined behavior the || 0 construct
is a good clean way of making sure your falses are actually integer/cleanly
printable.

Perl implicitly acknowledges data type differences in the fact that it uses
different binary operators for strings vs integers. Bool can occur in either
which is why the imprecise definition of what you will actually have in a
scalar when it's a bool result.

Bruce
 
A

A Dude

  AD> Then write (the perlish way)

  AD>     my $output_value = CONDITION || '0';

that is a poor choice of a false value. sure it works but 0 (no quotes)
or '' would be better.

It wasn't meant to be a false value, just to indicate one when
*writing it out* to read it back in, later. I specified the string
'0'. If the condition is not true.
 
A

A Dude

Note that this code does not do the same thing as the code quoted above.

It wasn't meant to. He was talking about making it 1 or 0 *not* for
their numerical value, but for "true" and "false". Collapsing "true"
to '1' is a *needless* step if all you're doing is persisting a value
that you are going to evaluate as a boolean to a file.

[...]
This code only normalizes false values to '0', leaving true values
in their original form.

Uh. Yeah. That's what it does. But the context is *displaying* boolean
values. "If I want to write it to a properties file to be read in
again...[omitted example] just feels amateurish and too verbose to me.
" The constraints Tim puts on it are unneeded.
 
A

A Dude

  AD>     $my_boolean=

  AD> is illustrative to me. (Unless it might be a ' ')

' ' is a true value. it would be foolish to ever use it as just a
boolean if you want to print it.

I forgot how much people on usenet like to argue--even if they have to
forget the context in order to do it.

The concept is the *illustrative value* of printing

$my_boolean=

Not the advisability of sticking just anything in $my_boolean.
On a standard terminal/console you can't tell that it's not a ' '.
That's all. I set it was illustrative enough, and I qualified that
with a case where if you accidentally stored a space in there, you
wouldn't be able to see the difference.

It really doesn't matter to me anyway. I use Smart::Comments or a
debugger. If I were to accidentally store a non-visible value in a
scalar meant as a boolean, those tools disambiguate the issue.

That's why I left off with advice to use more mature printing tools.
 
U

Uri Guttman

AD> It wasn't meant to be a false value, just to indicate one when
AD> *writing it out* to read it back in, later. I specified the string
AD> '0'. If the condition is not true.

i know what you did. please. my point is that setting the false value to
'0' is a poor idea in general. you don't write out booleans to text
files in most cases. data::dumper or storable can handle that for you
with any false value. so pick one that works better in other
situations. '0' is false but can be subtly odd if manipulated the wrong
way. it is harder to do that with '' or 0. sticking with the most common
false values is a good idea. use it as you wish.

uri
 
T

Tim McDaniel

It wasn't meant to. He was talking about making it 1 or 0 *not* for
their numerical value, but for "true" and "false".

Actually, I ran across a place a little while ago where I WAS using a
boolean where I would have liked a numerical value:
$command[$use_bash ? 1 : 0]
(where $use_bash had been set via a conditional before).
I could have made it
$command[$use_bash]
But that code and assumption has since gone away, when I needed
something with more complicated conditions.
 
P

Peter J. Holzer

AD> It wasn't meant to be a false value, just to indicate one when
AD> *writing it out* to read it back in, later. I specified the string
AD> '0'. If the condition is not true.

i know what you did. please. my point is that setting the false value to
'0' is a poor idea in general. you don't write out booleans to text
files in most cases.

"Most cases" doesn't matter. Here he wants to. And if the specification
of the file format says that a false value must be represented by the
character '0' (ASCII 0x30), then I find it clearer to use the string '0'
instead of the number 0 in perl code. Sure, print will convert the
number to the correct string, but if you want to print '0', write it.

(Of course in this case you must be sure that CONDITION returns the
right value in the "true" case. As we have seen, the true value of the
relational operators is not defines, so (($x < $y) || '0') is not
correct, you have to write ( $x < $y ? '1' : '0')[1]).
data::dumper or storable can handle that for you
with any false value.

Both produce a very perl-specific format. Unless the file is only
intended to be read by another Perl program (or a Perl programmer in the
case of Data::Dumper), they are not appropriate.

hp

[1] OTOH, perl has used 1 as the return value of the relational
operators for such a long time (probably since version 1) that this is
very unlikely to change even if it isn't defined.
 
P

Peter J. Holzer

I forgot how much people on usenet like to argue--even if they have to
forget the context in order to do it.

The concept is the *illustrative value* of printing

$my_boolean=

Not the advisability of sticking just anything in $my_boolean.
On a standard terminal/console you can't tell that it's not a ' '.

Well, on a standard terminal, you can't distinguish '0' from '0 ',
either, so that's rather pointless. If you are printing this only for
debugging reasons, you probably know about the context to tell that
"nothing visible printed" means false. If you don't, then you either
need to print delimiters (I usually use "<$variable>") or even write
some code to print invisible characters in hex (unfortunately,
Data::Dumper doesn't do this).
That's why I left off with advice to use more mature printing tools.

Right.

hp
 
P

Peter J. Holzer

Peter said:
(5) That "special false". I was going nuts trying to figure out what
was different between

[ '' in string context, 0 in numeric context ]
That special false is evaluated to blah-blah-blah *immediately* since
the context is known at compile time (am I right?).

No. Consider:

#!/usr/bin/perl
use warnings;
use strict;

my $bool = (1 < 0);

if (rand() < 0.5) {
print "<$bool>\n";
} else {
print 0 + $bool, "\n";
}

Anyone who applies a numeric operator to a logical value and expects
consistent results is asking for trouble.

The program above does produce consistent results and is perfectly
well-defined in Perl. I am not asking for trouble, but demonstrating a
perfectly well-defined (though somewhat surprising) property of the
scalar value returned by (1 < 0). (Interestingly, if I change (1 < 0) to
(0 < 1), then I am asking for trouble).
In strongly-typed languages you would get a compiler or run-time
error/warning, however perl is a scripting language and is built to be
flexible, assumes you know what you're doing and will silently oblige
even the most horrendous abuses.

You actually have the same issue in C: false is defined as 0 and true is
!false.

However, in C, !0 is defined as 1.

There is no "boolean" type in C (well, C99 has _bool, but ...) and all
the "logical" operators in C return a well-defined result (1 or 0) of
type int.

I have seen a discussion recently where someone was using an
library "elegantly" and came unstuck on a different platform because he
assumed that the true returned from that library was 1 (as it was on his
development platform). His usage became really interesting because the new
platform was returning -1 (binary all 1s), which is another common value
used for true.

This is however a problem with his use of this particular library, not a
problem with his use of C.

x = (1 > 0) + 5;

is perfectly well-defined in C and will always assign 6 to x.

If a function is defined as "returning a true value on success" of
course you cannot test this with if (function() == 1), you need to use
if (function()).

As a programmer you need to understand when you're crossing type boundaries

And you also need to know when you are *not* crossing type boundaries.
In C (1 > 0) + 5 doesn't cross a type boundary. Both (1 > 0) and 5 are
expressions of type int.

and make sure at that point you force defined behavior the || 0 construct
is a good clean way of making sure your falses are actually integer/cleanly
printable.

"actually integer" and "cleanly printable" have nothing to do with each
other. '', 'green', 'false' are all cleanly printable, but none of them
is an integer. The "special false" value is an integer (the integer
zero) and it is also printable (it prints as ''), but depending on your
expectations it may not be "cleanly printable" (a "normal" integer of
value 0 prints as '0', not '').

Perl implicitly acknowledges data type differences in the fact that it uses
different binary operators for strings vs integers.

Actually, it does this because there is *no* difference in the data
type. In a strongly typed language you can use the same operators and
the compiler (or run-time environment) can figure out which operation
was meant from the (static or dynamic) type of the arguments. In perl,
there are only scalars, so you have to tell it whether you want a string
or a numeric comparison[1]. (Similarily, in B, there were different
operators for integer and floating point operations, because B was
typeless).
Bool can occur in either which is why the imprecise definition of what
you will actually have in a scalar when it's a bool result.

I don't understand the last sentence.

Perl has a very precise definition what will be recogized as true and
false. It also has a definition what value (the "special false") will be
returned by the "logical" operators when they return false. For some
reason it doesn't define what these operators return for the true value.
I am very sure that this omission has nothing to do with the
number/string ambivalence of scalars. I tend to think that the omission
is a simple oversight, but it might be loosely defined as "any true
value" on purpose.

hp

[1] Strictly speaking the interpreter could figure it out at run-time.
But since the type (NV, IV, UV, PV, or a combination) can be changed
just by using a variable, this would be extremely confusing.
 
D

Dr.Ruud

Peter said:
As we have seen, the true value of the
relational operators is not defines, so (($x < $y) || '0') is not
correct, you have to write ( $x < $y ? '1' : '0')[1]).

I also see !! being used, like: !!($x < $y).


$ perl -we'
my ($x, $y) = (1, 2);
print q{<}, defined() ? qq{$_:} : q{undef:}, !!$_, qq{>\n} for
$x < $y,
$x > $y,
$x & $y,
$x && $y,
$x + $y,
undef,
q{},
q{ },
;
'
<1:1>
<:>
<0:>
<2:1>
<3:1>
<undef:>
<:>
< :1>
 
P

Peter J. Holzer

Peter said:
As we have seen, the true value of the
relational operators is not defines, so (($x < $y) || '0') is not
correct, you have to write ( $x < $y ? '1' : '0')[1]).

I also see !! being used, like: !!($x < $y).

That makes no sense. ($x < $y) already returns a "boolean" result (i.e.,
either the special false value or an undocumented true value (which
happens to be 1)). ! will negate this and the second ! will negate this
again, so the end result will still be either the special false value or
an undocumented true value (which happens to be 1).

If you trust ! to return 1 or special-false, you can also trust < to
return 1 or special false. If you don't trust < to return 1 or
special-false, you have no reason to trust ! to do this.

Where this idiom is useful is if you have an argument which is less
restricted. For example you have a function which returns a true value
on success (maybe even a "zero but true" value like '0E0') and false on
failure. Then you can count successful calls like this

my $count;
for (...) {
$count += !!my_function();
}

Of course this assumes that !0 is 1, which isn't documented.

In general, this idiom doesn't seem to be as useful in Perl as in C,
where !! always turns its argument into an integer with value 1 or 0.

hp
 
B

Bruce Cook

Peter said:
Peter said:
(5) That "special false". I was going nuts trying to figure out what
was different between

[ '' in string context, 0 in numeric context ]

That special false is evaluated to blah-blah-blah *immediately* since
the context is known at compile time (am I right?).

No. Consider:

#!/usr/bin/perl
use warnings;
use strict;

my $bool = (1 < 0);

if (rand() < 0.5) {
print "<$bool>\n";
} else {
print 0 + $bool, "\n";
}

Anyone who applies a numeric operator to a logical value and expects
consistent results is asking for trouble.

The program above does produce consistent results and is perfectly
well-defined in Perl. I am not asking for trouble, but demonstrating a
perfectly well-defined (though somewhat surprising) property of the
scalar value returned by (1 < 0). (Interestingly, if I change (1 < 0) to
(0 < 1), then I am asking for trouble).
In strongly-typed languages you would get a compiler or run-time
error/warning, however perl is a scripting language and is built to be
flexible, assumes you know what you're doing and will silently oblige
even the most horrendous abuses.

You actually have the same issue in C: false is defined as 0 and true is
!false.

However, in C, !0 is defined as 1.

This is where lots of people make mistakes in C.

if(a) is not the same as
if(a == !0)

Original C compilers had an easy way of doing conditionals; they would
assign a variable to a register and then branch on the Z flag. This worked
because !0 is any value with any bit set.
There is no "boolean" type in C (well, C99 has _bool, but ...) and all
the "logical" operators in C return a well-defined result (1 or 0) of
type int.

Yes, there are no bools, but conditionals in C work on zero and non-zero
integers.
This is however a problem with his use of this particular library, not a
problem with his use of C.

x = (1 > 0) + 5;

is perfectly well-defined in C and will always assign 6 to x.

If a function is defined as "returning a true value on success" of
course you cannot test this with if (function() == 1), you need to use
if (function()).

This example would work, however in some C compilers I have used
x=(2>0)+5 would always return 7. This is because the compiler worked with
not 0 being true, and the cheapest comparison on a particular platform is
sub.

This doesn't break comparison operators, but does give an unexpected result
when used as an integer result.
And you also need to know when you are *not* crossing type boundaries.
In C (1 > 0) + 5 doesn't cross a type boundary. Both (1 > 0) and 5 are
expressions of type int.



"actually integer" and "cleanly printable" have nothing to do with each
other. '', 'green', 'false' are all cleanly printable, but none of them
is an integer. The "special false" value is an integer (the integer
zero) and it is also printable (it prints as ''), but depending on your
expectations it may not be "cleanly printable" (a "normal" integer of
value 0 prints as '0', not '').

Sorry, you're mistaking C semantics for Perl. Perl does not treat scalars
as integers and so it's conditionals are more complex (and yes hacky) than
C. Especially the one you don't like, which is defining the behavior of a
string being used in a condition.
Perl implicitly acknowledges data type differences in the fact that it
uses different binary operators for strings vs integers.
[...]


Perl has a very precise definition what will be recogized as true and
false. It also has a definition what value (the "special false") will be
returned by the "logical" operators when they return false. For some
reason it doesn't define what these operators return for the true value.
I am very sure that this omission has nothing to do with the
number/string ambivalence of scalars. I tend to think that the omission
is a simple oversight, but it might be loosely defined as "any true
value" on purpose.

Perl defines false and any other value is true. This is not an omission.
In this way it does behave exactly the same way C does.

[...]


Bruce
 
P

Peter J. Holzer

Peter said:
Peter J. Holzer wrote:
(5) That "special false". I was going nuts trying to figure out what
was different between

[ '' in string context, 0 in numeric context ] [...]
Anyone who applies a numeric operator to a logical value and expects
consistent results is asking for trouble. [...]
In strongly-typed languages you would get a compiler or run-time
error/warning, however perl is a scripting language and is built to be
flexible, assumes you know what you're doing and will silently oblige
even the most horrendous abuses.

You actually have the same issue in C: false is defined as 0 and true is
!false.

However, in C, !0 is defined as 1.

This is where lots of people make mistakes in C.

You seem to be one of them.

if(a) is not the same as
if(a == !0)

I didn't say that. I said !0 is the same thing as 1 which means, that

if (a == !0)

is exactly the same as

if (a == 1)

While

if (a)

is the same thing as

if (a != 0)

Obviously (a != 0) and (a == 1) are not the same thing.

Original C compilers had an easy way of doing conditionals; they would
assign a variable to a register and then branch on the Z flag.

This may have been true on the PDP-11, although I doubt it. It certainly
wasn't a common feature of CPUs at the time. Most only set the flags as
the result of some computation, not a simple MOV. (There is a special
TST instruction to set the status flags depending on the contents of a
register)
This worked because !0 is any value with any bit set.

No. !0 is not any non-zero value. !0 is exactly 1. Any non-zero value is
treated as "true".


Yes, there are no bools, but conditionals in C work on zero and non-zero
integers.

Your "but" sounds like there is a contradiction. There isn't. C doesn't
have a boolean type and you can use any scalar type (not just
integers) where a true/false decision is needed (I think this is what
you mean by "conditional" - correct me if I'm wrong). The result of the
relational, equality and logical operators is defined as having type
int, thus there is no "crossing a type boundary" when you use them in an
arithmetic expression. Such a type boundary may exist in the mind of a
Pascal programmer, but it doesn't exist in C.


This example would work, however in some C compilers I have used
x=(2>0)+5 would always return 7.

Then they were not C compilers.

Each of the operators < (less than), > (greater than), <= (less than
or equal to), and >= (greater than or equal to) shall yield 1 if the
specified relation is true and 0 if it is false.89) The result has
type int.

(ISO-9899:1999. A similar definition is in Appendix A, section
7.6 of K&R I, German translation (I don't have the original)


This is because the compiler worked with not 0 being true, and the
cheapest comparison on a particular platform is sub.

So the result of

(-2 > 0)

would be -2 (i.e., true)? I think you should think about this a bit
more.

This doesn't break comparison operators,

If (-2 > 0) is true that's pretty broken by any measure. If a compiler
produces a different result than the C specification says it should, it
is still broken.

Sorry, you're mistaking C semantics for Perl.

No, I'm not. I don't see where you see any C semantics in the paragraph
above. C simply doesn't have scalars which may be an integer and a
string at the same time. This is quite Perl-specific.


Perl does not treat scalars as integers and so it's conditionals are
more complex (and yes hacky) than C. Especially the one you don't
like, which is defining the behavior of a string being used in a
condition.

Who said I don't like it? I never said such a thing. I don't even think
it is very complex. The number 0, the strings '' and '0' and the undef
value are false, all other scalars are true.

Perl defines false and any other value is true.

You don't seem to understand the difference between

1) what is recognised as true in a conditional expression and
2) what a comparison or logical operator returns as a true value

These are not the same thing.
This is not an omission. In this way it does behave exactly the same
way C does.

No it is not.

C does define that the result of the expression (0 < 1) is 1. If your
compiler produces a different result, it is broken.

Perl only defines that the result of the expression (0 < 1) must be
true. It could be 1, -1, 'true', 42, a reference to a hash, whatever.

However, every version of perl (note: lower case 'p') since at least
perl4 (probably perl1) has always returned 1 as the true value for the
comparison operators (==, !=. <. >. <=, >=, eq, ne, lt, gt, le, ge) and
the logical negation (!, not). It is not clear to me whether this is
undocumented because @Larry want to keep the option of changing it one
day (in this case, why is the false value documented? The ''/0 mixture
is rather bizarre and it seems much more likely that one would like to
change that in some future revision of the language), or whether it is
simply undocumented because it's the same as in C and "people know that
anyway, so we don't have to write it down". (Perl documentation has
become more self-sufficient over the years, but originally it assumed a
lot of general Unix knowledge and there are still spots which are only
comprehensible if you have a background as a Unix/C programmer - this
might be one of them)

hp
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top