# Spaceship and NaNs

- Thread: https://externals.io/message/86670
- Original archive: https://news-web.php.net/php.internals/86670
- Started by Dmitry Stogov on 2015-06-15T19:44:46+00:00
- Messages: 7
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #86670 — Dmitry Stogov — 2015-06-15T19:44:46+00:00

URL: https://externals.io/message/86670#86670

Hi,

I found a problem with spaceship operator.
It doesn't define result for comparison with NaN.

$ sapi/cli/php -r 'var_dump(sqrt(-1) <=> 0);'
int(-1)
$ sapi/cli/php -r 'var_dump(0 <=> sqrt(-1));'
int(-1)

$ sapi/cli/php -r 'var_dump(0 < sqrt(-1));'
bool(false)

all other comparison operators return "false" as well.

Thanks. Dmitry.

---

## #86672 — Bob Weinand — 2015-06-15T19:55:04+00:00

URL: https://externals.io/message/86670#86672 · In reply to: #86670

As far as I know, we made it that way in order to enforce an int return type all the time.
int(-1) is indeed the sensible value for this. (Mainly int(0) does not work because it'd mean equality and so we're left with int(-1) and int(1).)

Just because other comparison ops already return a bool, we can return bool(false) there.

Bob

> Am 15.06.2015 um 21:44 schrieb Dmitry Stogov <dmitry@zend.com>:
> 
> Hi,
> 
> I found a problem with spaceship operator.
> It doesn't define result for comparison with NaN.
> 
> $ sapi/cli/php -r 'var_dump(sqrt(-1) <=> 0);'
> int(-1)
> $ sapi/cli/php -r 'var_dump(0 <=> sqrt(-1));'
> int(-1)
> 
> $ sapi/cli/php -r 'var_dump(0 < sqrt(-1));'
> bool(false)
> 
> all other comparison operators return "false" as well.
> 
> Thanks. Dmitry.

---

## #86673 — Anatol Belski — 2015-06-15T20:11:54+00:00

URL: https://externals.io/message/86670#86673 · In reply to: #86672

> -----Original Message-----
> From: Bob Weinand [mailto:bobwei9@hotmail.com]
> Sent: Monday, June 15, 2015 9:55 PM
> To: Dmitry Stogov
> Cc: davey@php.net; Andrea Faulds; Stanislav Malyshev; Anatol Belski; Kalle
> Sommer Nielsen; PHP Internals
> Subject: Re: [PHP-DEV] Spaceship and NaNs
> 
> As far as I know, we made it that way in order to enforce an int return
type all
> the time.
> int(-1) is indeed the sensible value for this. (Mainly int(0) does not
work because
> it'd mean equality and so we're left with int(-1) and int(1).)
> 
> Just because other comparison ops already return a bool, we can return
> bool(false) there.
> 
> Bob
> 
> > […]
false were correct, IMHO. Btw looks like the same case is with `NAN` <=> NAN.

Regards

Anatol

---

## #86678 — Stanislav Malyshev — 2015-06-15T20:44:28+00:00

URL: https://externals.io/message/86670#86678 · In reply to: #86670

Hi!

> I found a problem with spaceship operator.
> It doesn't define result for comparison with NaN.
> 
> $ sapi/cli/php -r 'var_dump(sqrt(-1) <=> 0);'
> int(-1)
> $ sapi/cli/php -r 'var_dump(0 <=> sqrt(-1));'
> int(-1)
> 
> $ sapi/cli/php -r 'var_dump(0 < sqrt(-1));'
> bool(false)
> 
> all other comparison operators return "false" as well.

I think <=> is defined as:
1. if < returns true, then negative
2. if == returns true, then 0
3. otherwise, positive

https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#relational-operators

So the result here is wrong I assume. I suspect this is the consequence
of how compare_function treats IS_DOUBLE - it first subtracts them
(which produces NaN) and then does ZEND_NORMALIZE_BOOL - which is:

#define ZEND_NORMALIZE_BOOL(n)			\
	((n) ? (((n)>0) ? 1 : -1) : 0)

Since NaN > 0 is false, what we get is -1. I guess we should add check
for NaN in either ZEND_NORMALIZE_BOOL or comparison routine, but not
sure what comparing to NaN should produce... Always false? AFAIK NaN is
not equal to NaN so that may be the best option.
The individual comparison operators already return false with NaN but I
suspect not for the right reasons...
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #86679 — Rowan Collins — 2015-06-15T20:45:53+00:00

URL: https://externals.io/message/86670#86679 · In reply to: #86672

>As far as I know, we made it that way in order to enforce an int return
>type all the time.
>int(-1) is indeed the sensible value for this. (Mainly int(0) does not
>work because it'd mean equality and so we're left with int(-1) and
>int(1).)
>
>Just because other comparison ops already return a bool, we can return
>bool(false) there.

This makes a lot of sense. If it returned false, that would just be cast to 0 in most situations, implying that NaN is equal to everything (rather than nothing). In other situations, it would simply lead to an error. The operator would lose much of its value if it had to be surrounded with error traps and caveats because it didn't reliably return an integer.

Regards,
-- 
Rowan Collins
[IMSoP]

---

## #86681 — Bishop Bettini — 2015-06-15T21:00:27+00:00

URL: https://externals.io/message/86670#86681 · In reply to: #86679

On Mon, Jun 15, 2015 at 4:45 PM, Rowan Collins <rowan.collins@gmail.com>
wrote:

> 
> > […]
>
> This makes a lot of sense. If it returned false, that would just be cast
> to 0 in most situations, implying that NaN is equal to everything (rather
> than nothing). In other situations, it would simply lead to an error. The
> operator would lose much of its value if it had to be surrounded with error
> traps and caveats because it didn't reliably return an integer.
>

Convenience aside, I think it has to be false, or an ERROR, or something
other than int.

Clause 5.11, paragraph 2 of the 754-2008 standard reads:

Four mutually exclusive relations are possible: less than, equal, greater
> than, and unordered. The last case arises when at least one operand is NaN.
> Every NaN shall compare unordered with everything, including itself.


Personally, I'd vote false for consistency and immediacy.  Then, I'd
suggest we look at handling NaN more predictably.  Pretty much whenever NaN
enters as a data point, the end result will be NaN, and I want to know that
as early as possible.  Like an ERROR.

bishop

---

## #86684 — Stanislav Malyshev — 2015-06-15T21:19:05+00:00

URL: https://externals.io/message/86670#86684 · In reply to: #86679

Hi!

> > […]

But we can not return bool from operator that is declared as returning
int, and adding extra type would make this operator essentially useless,
as it is meant to be a concise way of comparing two things, and if after
that you need to write a parser to figure out what it returned, it's
much easier to just go back to basic comparison operators.

Since not everything among PHP values is well-ordered, there would be
sets of values for which comparison does not make intuitive sense - i.e.
both < and > are false, etc. In this case, there is no intuitive value
to return, but there should be a well-defined one to return, and we have
a pretty good definition here I think:

https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#relational-operators
-- 
Stas Malyshev
smalyshev@gmail.com
