Integer operations are implementation-defined

From: Date: Wed, 30 Jul 2014 18:29:39 +0000
Subject: Integer operations are implementation-defined
Groups: php.standards 
Request: Send a blank email to standards-+get-134@lists.php.net to get a copy of this message
Hi, The draft spec is great, but one particular part of it really bothers me: > Certain operations on integer values produce a mathematical result that cannot be represented > as an integer. Examples include the following: > * Incrementing the largest value or decrementing the smallest value > * Applying the unary minus to the smallest value > * Multiplying, adding, or subtracting two values > In such cases, the resulting type and value is implementation-defined, but must be one of the > following: > * The computation is done as though the types of the values were float with the result having > that type > * The result type is int and the value reflects wrap-around (for example adding 1 to the > largest value results in the smallest value) > * The computation is done as though the type had some unspecified, arithmetic-like object type > with the result being mathematically correct I really don’t like this. The specification is supposedly based off php.net PHP 5.6, as far as I know. However, php.net PHP never wraps around integers for standard operations, it always promotes to float. By allowing implementations to wrap around rather than promote to float, we are making sure PHP code cannot be written as “write-once, run anywhere” as it may have completely different results on two different implementations. Now, I assume the reason for having this wording is because HHVM wraps. However, frankly, while it might make writing a JIT slightly easier and it might be nicer for performance, that doesn’t mean HHVM’s behaviour is correct. Wrapping around is convenient from a CPU standpoint but it is not appropriate in a high-level language which should abstract away implementation differences, and it also doesn’t really make much sense. php.net PHP’s behaviour isn’t perfect as beyond 53-bits you lose precision, but at least the sign and rough magnitude are kept intact if I do PHP_INT_MAX + 1. On the other hand, if we wrap, we end up with the minimum value, so we lose both sign and magnitude, making the result completely useless. Furthermore, permitting wrapping breaks PHP’s traditional weak typing guarantees that two integers added should have the same result as two floats added, or a float and an int, or an int and a float, or even two strings. PHP has slowly been moving towards being more consistent across platforms (see the 64-bit RFC for example). We should not let one runtime do a completely different thing for ints and break weak typing purely because it is more convenient to implement. There should be one thing PHP is defined to do, and it should do it consistently across platforms. Of course, integer size will inevitably vary (unless my bigints RFC makes it in ;), but if I add 0x7FFFFFFF and 1 it should at least result in a value of the same magnitude and sign on both 64-bit and 32-bit platforms, accurate to the last digit or not. Therefore, I propose that section to simply read as follows: > In such cases, the computation is done as though the types of the values were float with the > result having that type. This is what php.net PHP does, this is what most PHP code (except that which HHVM has broken and has had to implement workarounds to deal with HHVM’s incorrect behaviour) relies on, and it is what PHP should do in future lest we switch to arbitrarily-sized integers. I should clarify I wish no ill-will towards the HHVM team. The work they are doing is amazing and it is great to see competition. However, I believe strongly that PHP should be consistent across implementations and platforms as much as possible. Doing the right thing might be inconvenient, but it would mean less fragmentation and actually give the spec more meaning as we can standardise on a single behaviour. Thanks! -- Andrea Faulds http://ajf.me/

« previous php.standards (#134) next »