The whole point of loose typing

I don't know John Lim, but he linked to a Livejournal post where someone complained about their expectations being dashed when trying various comparisons.


<?php

$a = 0;
$b = "eggs";
$c = "spam";

print ($a == $b) ? "a == b\n" : "a != b\n";
print ($b == $c) ? "b == c\n" : "b != c\n";
print ($a == $c) ? "a == c\n" : "a != c\n";
print ($a == $d) ? "a == d\n" : "a != d\n";
print ($b == $d) ? "b == d\n" : "b != d\n";
print ($c == $d) ? "c == d\n" : "c != d\n";

?>

% php equality.php
a == b
b != c
a == c
a == d
b != d
c != d

They proceed to be pretty confused by what could be perceived as confusing behavior. PHP does some type juggling in the background.

First, let's examine what happens when we cast various common values as booleans. There are two type specifiers because I specify each item as the type and the value, and then cast that.


/* Plain old true and false values */
(boolean) (boolean) true === (boolean) true
(boolean) (boolean) false === (boolean) false

/* A NULL, which is a special value */
(boolean) (NULL) NULL === (boolean) false

/* An empty string */
(boolean) (string) '' === (boolean) false

/* The numbers zero and one */
(boolean) (integer) 0 === (boolean) false
(boolean) (integer) 1 === (boolean) true

/* Other non-zero numbers (this behavior is just like C) */
(boolean) (integer) -1 === (boolean) true
(boolean) (integer) 100 === (boolean) true

/* The number zero in string form: the string zero */
(boolean) (string) '0' === (boolean) false

/* An empty array */
(boolean) (array) array() === (boolean) false;

/* Non-empty arrays */
(boolean) (array) array(0) === (boolean) true;
(boolean) (array) array(1) === (boolean) true;
(boolean) (array) array(0, 1) === (boolean) true;

/* A non-empty string */
(boolean) (string) 'in the hay' === (boolean) true

/* A tricky non-empty string */
(boolean) (string) 'false' === (boolean) true

/* Really tricky non-empty strings
* I might actually take issue with these,
* because they are really sneaky, but
* what is (probably) happening is that
* first the strings get converted into integers
* and then booleans.
*/
(boolean) (string) '0 is awesome' === (boolean) true
(boolean) (string) ' 0' === (boolean) true

/* That notion seems to be help up by this test: */
(boolean) (string) '1' === (boolean) true

/* Fortunately, it is not completely ridiculous */
(boolean) (string) 'awesome is 0' === (boolean) true

So what is going on in that "crazy" example? One of the things to point out is that non-empty non-numeric strings are being compared to the number zero. My guess is that the zero is being juggled into a string since the string cannot be juggled into a number.


<?php

$a = 0;
$b = "eggs";
$c = "spam";

/*
(string) $a is '0';
(string) $d is 0 (because it is not set)
(string) $d is '' (because it is not set)
*/

print ($a == $b) ? "(string) a == (string) b\n" : "(string) a != (string) b\n";
print ($b == $c) ? "(string) b == (string) c\n" : "(string) b != (string) c\n";
print ($a == $c) ? "(string) a == (string) c\n" : "(string) a != (string) c\n";
print ($a == $d) ? "(int) a == (int) d\n" : "(int) a != (int) d\n";
print ($b == $d) ? "(string) b == (string) d\n" : "(string) b != (string) d\n";
print ($c == $d) ? "(string) c == (string) d\n" : "(string) c != (string) d\n";

?>

% php equality.php
(string) a == (string) b
(string) b != (string) c
(string) a == (string) c
(int) a == (int) d
(string) b != (string) d
(string) c != (string) d

I wouldn't mind a more strongly typed language sometimes, and I might have made different design decisions, but they were made for a reason.

Another site on the internet lamented the fact that strpos() returns a false on failure and a 0 if the string match happens at the zero index, complaining that the required code is not very clear.


if (false !== strpos('haystack', 'needle')) {
echo 'Found it!';
}

Their comment was that this (the C syntax) would be oh-so-much-better:


if (-1 < strpos('haystack', 'needle')) {
echo 'Found it!';
}

Wow. That's so much clearer! I suppose that the meat of their problem was that one has to use the !== operator instead of the != operator to check for false. Yes, strpos is kind of a hassle that way, but if it really bothers you, it is trivially easy to write a wrapper function.


/* Note that I am Elliot-Smithing the argument order */
function needle_in_the_hay($needle, $haystack) {
return (false !== strpos($haystack, $needle);
}

The real problem here is that strpos in C is for finding a single character in another string and is being abused in php to find whole strings in other strings. Better to pick a new name for that purpose. Even so, ultimately it's just an excuse to whine about PHP. It's not a perfect language, but it is what it is.

You could really make the complaint that there should be a String class with methods and stuff like that. I would accept that complaint... and then ask why you aren't writing that class. You know you want to!

Oh, php has a nice chart of comparisons.

http://us.php.net/manual/en/types.comparisons.php

1 Responses to The whole point of loose typing

  1. 986 SneakyWho_am_i 1229330366

    Yeah.... Any complaints about loose typing fall over the very second you do a strict comparison. The fact that php can cast to type and do strict comparisons really invalidates most arguments about the weak versus strong typing.
    I for one would like if ther ewas soime something like a php.ini setting I could use to force stricter typing, but it wouldn't change the capabilities of the language -- it would only encourage me to write sloppier and less secure code (compare to magic_quotes_gpc).

    So, loose typing just saves us work; we don't have to cast to type or strictly check. We don't "have" to, but that doesn't mean that we "can't"..... Big difference!

    The thing with strpos() when we compare it to C is that C really doesn't really understand booleans. This is by no means a design limitation but really, thinking about it, if the substring appears at a certain position then we expect a number back! Is "-1" a number? Yes it is! A computer can't be expected to know the lower and upper bounds of this without some kind of programmer to decide it in the first place!

    Now, when strpos() doesn't find a match, instead of returning an invalid numeric value it (consistently, I might point out) returns false. False isn't even a number, so it's very safe!

    In summary, +1 @ the entire post

Leave a Reply

About You