Syntactic Confectionery Delight PerlMonks

### "2" | "8" = ":" and 2|8=10

by MSoegtropIMC (Initiate)
 on Nov 04, 2011 at 11:41 UTC Need Help??
MSoegtropIMC has asked for the wisdom of the Perl Monks concerning the following question:

Dear Perl Monks

Perl handles the bitwise operators on integers and strings differently. E.g. "2"|"8" = ":" (bitwise ascii) while 2|10 = 12. So there are places in perl, where it makes a difference if a scalar is a string or an integer. Yet there doesn't seem to be a way to find out if a scalar is an integer or string. All the references I found go back to a regexp match, but this way I cannot distinguish between an integer and a string. Is there a way?

And yes, I know how to force a string to an integer using int().

Best regards,

Michael

Replies are listed 'Best First'.
Re: "2" | "8" = ":" and 2|8=10
by bart (Canon) on Nov 04, 2011 at 12:07 UTC
You're right. Bitwise operators are the only place where there's a difference between strings and numbers. BTW This difference does not fit into the philosophy of Perl, where you should not be able to distinguish between strings and numbers, so this is actually a language design flaw.

You could detect if a scalar is a string or a number, without resorting to XS, by making use of this different behavior. If you use bitwise XOR (^) and XOR a scalar with itself, you'll get the value 0 if it was a number, and a string of null bytes ("\0") with the original string length of the argument, if it was a string. Yes, even if the number doesn't fit into an integer, like 1E99.

I think this will work:

```sub is_number {
my \$arg = shift;
return defined \$arg && !ref \$arg && (\$arg^\$arg) eq '0';
}
BTW dual-vars, like !1, are treated as a number.
BTW This difference does not fit into the philosophy of Perl, where you should not be able to distinguish between strings and numbers, so this is actually a language design flaw.

Agreed. Perl always had the philosophy that the operators determine the operation, not the type of the operands. Perl 6 solves this by adding type modifiers for the bitwise operators:

```  \$a +| \$b;  # Integer bitwise OR
\$a ~| \$b;  # String bitwise OR
\$a ?| \$b   # logical OR

It makes the bitwise operators look a bit more ugly, but I don't really mind because I don't use them very often. This change has the additional benefit of freeing up the characters that perl 5 uses for bitwise operators.

(Note that || as a logical OR still exists; the difference is that || returns the first true value, whereas ?| always returns a Bool).

Bitwise operators are the only place where there's a difference between strings and numbers.
No. It matters for post-increment as well.
BTW This difference does not fit into the philosophy of Perl, where you should not be able to distinguish between strings and numbers, so this is actually a language design flaw.
It's a deliberate decision, and well worth the offset. It allows you to use bitfields that aren't restricted to 32 (or 64) bits.
Bitwise operators are the only place where there's a difference between strings and numbers.
No. It matters for post-increment as well.
I think you're wrong there. Postincrement only works different for strings if they start with a letter. For strings like "199" it makes no difference: you just get 200. And other strings apparently are converted to a number first, as \$x = "2A"; \$x++ produces 3.
It's a deliberate decision, and well worth the offset. It allows you to use bitfields that aren't restricted to 32 (or 64) bits.
Yes, I don't question the functionality, that is useful. But the typical Perl thing to do would have been to provide different operators for strings and for numbers. Just as with = vs eq and + vs ..
Re: "2" | "8" = ":" and 2|8=10
by BrowserUk (Pope) on Nov 04, 2011 at 12:10 UTC
I cannot distinguish between an integer and a string. Is there a way?

You shouldn't need to discover whether a scalar actually contains the number or its string representation. The logic of your program will define which type of bitwise operation you want, and you can easily force this to be used.

If you want to do integer bitwise operation:

```my \$res = 0+\$x | 0+\$y;

If you want stringy bitwise use:

```my \$res  = ''.\$x | ''.\$y;

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
Re: "2" | "8" = ":" and 2|8=10
by jethro (Monsignor) on Nov 04, 2011 at 11:48 UTC

Should there? When it does matter, you can and should force the correct interpretation of the variable

PS: To force an integer to be interpreted as a string use "\$n"

Re: "2" | "8" = ":" and 2|8=10
by syphilis (Chancellor) on Nov 04, 2011 at 12:38 UTC
I think that if I *really* did need to know whether the variable had one of the numeric flags set, then I'd probably use an XSub ... something like:
```use warnings;
use strict;

use Inline C => Config =>
BUILD_NOISY => 1;

use Inline C =><<'EOC';

int is_num(SV * x) {
if(SvIOK(x) || SvUOK(x) || SvNOK(x)) return 1;
return 0;
}

EOC

my \$ui = ~0;

print is_num(2), "\n";
print is_num("2"), "\n";
print is_num(\$ui), "\n";
print is_num("\$ui"), "\n";
print is_num(2.3), "\n";
print is_num("2.3"), "\n";
I know how to force a string to an integer using int()

The usual way to force numeric context is to add 0 (as already demonstrated) or multiply by 1. Using int() will truncate fractional values, thereby altering them.

Cheers,
Rob

Note: This doesn't take magic into account. The bitwise ops sure do.

```print is_num(\$|), "\n";   # 0
\$|=1;
print is_num(\$|), "\n";   # 0
print 1   | "A", "\n";
print "1" | "A", "\n";
print \$|  | "A", "\n";    # Acts as if \$| is numeric

Note: SvUOK(x) will always be false if SvIOK(x) is false, and SvNIOK(x) is more efficient than SvIOK(x) || SvNOK(x).

Re: "2" | "8" = ":" and 2|8=10
by ww (Archbishop) on Nov 04, 2011 at 12:12 UTC
misread OP or it has changed? Hunhhhh?

OP's bitwise OR of a string doesn't puzzle me, but "2|10 = 12" does.

```perl -e "use 5.012; say 2|8;"
10

and that's even an example (*nix style quoting), in perlop:

print "false\n" if (8 | 2) != 10;
Re: "2" | "8" = ":" and 2|8=10
by ikegami (Pope) on Nov 04, 2011 at 19:27 UTC

So there are places in perl, where it makes a difference if a scalar is a string or an integer.

Unfortunately, yes. Post-increment, post-decrement and syscall also have that problem.

Yet there doesn't seem to be a way to find out if a scalar is an if a scalar is an integer or string.

...or both or neither.

Maybe, but there's no need for one unless you are planning on introducing such problems into your own code.

If you want a string bitwise operator, coerce the value into a string ("".\$x). If you want a numeric bitwise operator, coerce the value into a number (0+\$x).

Create A New User
Node Status?
node history
Node Type: perlquestion [id://935898]
Approved by ww
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2018-05-28 00:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?
World peace can best be achieved by:

Results (198 votes). Check out past polls.

Notices?