Re: ||= (poorly documented?)
by frozenwithjoy (Priest) on Jul 09, 2012 at 05:55 UTC
|
You are almost correct in understanding how it works. Whatever is on the right side of the ||= operator is used if the left side evaluates to undef, like you said; however, it is also used if the left evaluates to false.
my $string;
$string ||= "Oh noes! Your variable was undef or false!";
I believe //, on the other hand, only tests for whether the left side is defined (but not for truthiness). | [reply] [Watch: Dir/Any] [d/l] [select] |
Re: ||= (poorly documented?)
by kcott (Archbishop) on Jul 09, 2012 at 06:02 UTC
|
$x ||= 2;
is equivalent to
$x = $x || 2;
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: ||= (poorly documented?)
by tobyink (Canon) on Jul 09, 2012 at 06:54 UTC
|
In general, where X is an existing operator, then:
$foo X= $bar;
# is short for:
$foo = $foo X $bar;
Practical examples:
$foo += $bar;
# is short for:
$foo = $foo + $bar;
$foo ||= $bar;
# is short for:
$foo = $foo || $bar;
$foo .= $bar;
# is short for:
$foo = $foo . $bar;
$foo *= $bar;
# is short for:
$foo = $foo * $bar;
This convention originally comes from Algol 68, but was made popular by C/C++ and is also available in many other languages (Java, Ruby, Python, Javascript, PHP, etc).
I would suppose that the reason these aren't documented in detail in perlop would be that people are expected to be already familiar with the convention. The Perl documentation probably shouldn't assume familiarity with other programming languages, but (especially for the older parts of the manual) they often seem to.
By the way, what the code you originally posted does is this: it creates a file handle $FH by opening the file with IO::File, but uses a hash %OUTFH in order to cache the file handles, and avoid opening the same file twice.
A longer way of writing the same thing would be:
$OUTFH{$name} = $OUTFH{$name} || IO::File->new(">g:\\perl_scripts\\$na
+me.log");
$FH = $OUTFH{$name} or die $!;
It's actually a fairly common construct. The poor man's memoization...
my $result = $cache{$input} ||= my_function($input);
... and probably ought to be documented in some of those lists of Perl idioms.
perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: ||= (poorly documented?)
by Marshall (Canon) on Jul 09, 2012 at 07:36 UTC
|
#!/usr/bin/perl -w
use strict;
## The ||= operator tests for "truthfulness"
## The //= operator tests for "definedness"
my $z = 25;
my $x = 550;
$z ||= $x;
print "$z\n"; #prints 25 because z is already true
my $y; # $y is undefined
print "y is not defined\n" if !defined $y;
$y //= 32;
print "y is is defined now as $y\n" if defined $y;
my $k; #$k is undefined
#An undefined value evaluates to "false"
#and the assignment proceeds
$k ||= 3842;
print "k is $k ...hey I'm defined now!\n";
__END__
25
y is not defined
y is is defined now as 32
k is 3842 ...hey I'm defined now!
Update:
There is a rather strange thing that can happen in Perl.
It is possible for Perl to return a "true", "zero" value.
It does this by returning the string "0E0": 0 * 10**1 =0
numerically, but that evaluates to "true" in a logical sense.
This is used in the Database Interface for example. You
might get back an answer "hey I worked, but I didn't modify
any rows!". In an language like C or Java, you have to have
two variables: Number of rows and did it work or not? In
Perl this can be expressed in a single value. "I worked, but
didn't modify any rows!". A "0" is logical False while a 0E0 is logical
True- pretty cool!
Update:
I got off track, but since I'm talking about 0E0, I will show
some code for your amusement.
#!/usr/bin/perl -w
#use strict;
$|=1; #Turn off STDOUT Buffering
# This is wild but Perl has
# a special string that will evaluate
# to a "true", "zero" value and can be used
# in a numeric computation - even with
# warnings!
# This is so obscure that it must be
# depreciated in favor of the 0E0 notation.
# I personally wouldn't use this, and I
# show it just for amusement. This just
# Perl trivia.
my $str_zero = "0 but true"; ### special string ###
$str_zero += 1;
print "new str_zero is: $str_zero\n";
# No warning, this is the same as 0E0
my $bogus_zero = "0 bogus";
$bogus_zero +=1;
print "bogus_zero plus one is: $bogus_zero\n";
# "works" albeit with a warning
__END__
new str_zero is: 1
Argument "0 bogus" isn't numeric in addition
(+) at C:\TEMP\zeroButTrue.pl line 23.
bogus_zero plus one is: 1
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
There is a rather strange thing that can happen in Perl.
It is possible for Perl to return a "true", "zero" value.
It does this by returning the string "0E0": 0 * 10**1 =0 numerically, but that evaluates to "true" in a logical sense.
This works because there are only two strings which evaluate as false in Perl: "" and "0".
Any other string which begins with one or more zeroes followed by a non-digit character will by logically true (since it's not one of the two false strings) while still having the value 0 when evaluated as a number. This actually will also work with strings that start with a non-numeric character (true as a boolean, 0 as a number), but, if warnings are enabled (as they generally should be), it will complain that "Argument "..." isn't numeric" if you try to use it as a number.
Aside from "0E0", the other string I often see used for this purpose (I'm not sure which is more common) is "0 but true".
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
I don't see how you and I are in any kind of disagreement.
| [reply] [Watch: Dir/Any] |
|
Re: ||= (poorly documented?)
by DrHyde (Prior) on Jul 09, 2012 at 09:55 UTC
|
You're almost right - ||= checks for *truth*, not definedness. Consider the case where $OUTFH{$name} == 0 - that is, it's defined but not true. | [reply] [Watch: Dir/Any] [d/l] |
Re: ||= (poorly documented?)
by Anonymous Monk on Jul 09, 2012 at 06:21 UTC
|
This is really poorly documented... Yes, if you only go by perldoc.perl.org/perlop.html, looking only for |=", it is poorly documented.
| [reply] [Watch: Dir/Any] |
|
To be fair, some things are a pain in the ass to google properly (especially if you aren't familiar with the topic in the first place). Also, documentation always makes more sense when you already know the topic. :P
| [reply] [Watch: Dir/Any] |
|
This actually is easily googleable... if you're deep enough into the Perl culture. Try searching for it under the name "orcish maneuver", which will explain not only what the operator is but also exactly how it's being used in this case. (Link is to duckduckgo's first result, which just happens to also be on PerlMonks.)
Also note that, because of the distinction between truthiness and definedness mentioned in previous replies, you're going to want to use //= instead of ||= in the vast majority of cases unless your code needs to support pre-5.10 versions of Perl.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
| [reply] [Watch: Dir/Any] |
|
|
To be fair, some things are a pain in the ass to google properly (especially if you aren't familiar with the topic in the first place). Also, documentation always makes more sense when you already know the topic. :P
That is not what I'm talking about since the OP was able to find perlop, but the problem was, it merely listed ||= it didn't explain much about it.
You had to read large chunks of perlop to figure out ||= is two operators in one, assignment and logical-or, and even then it didn't explain truthiness
On truthiness
How ||= works , its FAQ even though it doesn't search that way :)
Found 9 nodes roughly between 2012-07-09 and 1999-10-04 (searched 100.00% of DB).
where title contains "||="
| [reply] [Watch: Dir/Any] |
Re: ||= (poorly documented?)
by Anonymous Monk on Jul 09, 2012 at 06:36 UTC
|
Yep, that is right and it works the way it reads.
perl -e "my $shoo = 50; $shoo ||= 100; print $shoo;"
Prints
50
Should be the same as,
perl -e "$shoo=50; $shoo = ($shoo)?50 : 100;print $shoo;"
If you scroll down in perlop you'll see that style used to describe what // does, so they appear to be equivalent.
Celebrate Intellectual Diversity
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
If you scroll down in perlop you'll see that style used to describe what // does, so they appear to be equivalent.
|| tests for truthiness (and, therefore, definedness), whereas // only tests for definedness.
| [reply] [Watch: Dir/Any] [d/l] [select] |