Greetings internal,
I'm proposing a new RFC which would warn when an implicit conversion
from float to int occurs.
The draft is currently located on GitHub:
https://github.com/Girgias/float-int-warning/
for ease of commenting/providing changes to it.
The official discussion phase wouldn't start before I convert it to docwiki
and
post it on the wiki, something I'm planning to do next week.
Any feedback is appreciated.
Best regards,
George P. Banyard
Greetings internal,
I'm proposing a new RFC which would warn when an implicit conversion
from float to int occurs.The draft is currently located on GitHub:
https://github.com/Girgias/float-int-warning/
for ease of commenting/providing changes to it.The official discussion phase wouldn't start before I convert it to docwiki
and
post it on the wiki, something I'm planning to do next week.Any feedback is appreciated.
Best regards,
George P. Banyard
Hi George,
Thank you for this proposal, I'm all for it, though I'd go one step
further, and actually issue a warning during explicit casting as well:
(int) 3.5; // E_WARNING
(int) round(3.5); // OK
In my experience, it's better to be explicit about your intent, so forcing
the user to round()
before casting when the float has a fractional part is
OK to me.
This would help prevent weird silent conversions such as when you cast to
(int) from user input:
$age = $_GET['age']; // '25.75'
$x = (int) $foo; // I'd expect a warning, not a silent conversion to 25
— Benjamin
$age = $_GET['age']; // '25.75'
$x = (int) $foo; // I'd expect a warning, not a silent conversion to 25
If we want to make explicit casts "fussy", that would be a much bigger
change. Right now, the following are all valid, with no warnings, even
though they are all lossy conversions:
(int)25.75,
(int)"25.75",
(int)"hello",
(int)"99 red balloons",
(bool)2,
(bool)"yes",
(float)"3.1415 is not pi",
(string)M_PI, // calling this "lossy" is a bit of a stretch, but it
will retain decimal rather than binary precision
There's a case to be made for "strict casts" - I've pointed out before
that so-called "strict types" mode encourages users to write code that
is actually less strict, because explicit casts are very forgiving.
However, they should probably be a new syntax, because there will be an
ENORMOUS amount of code using deliberately using the existing casts in
lossy situations.
Regards,
--
Rowan Tommins
[IMSoP]
On Thu, 4 Feb 2021 at 17:55, Benjamin Morel benjamin.morel@gmail.com
wrote:
Greetings internal,
I'm proposing a new RFC which would warn when an implicit conversion
from float to int occurs.The draft is currently located on GitHub:
https://github.com/Girgias/float-int-warning/
for ease of commenting/providing changes to it.The official discussion phase wouldn't start before I convert it to
docwiki
and
post it on the wiki, something I'm planning to do next week.Any feedback is appreciated.
Best regards,
George P. Banyard
Hi George,
Thank you for this proposal, I'm all for it, though I'd go one step
further, and actually issue a warning during explicit casting as well:(int) 3.5; //
E_WARNING
(int) round(3.5); // OKIn my experience, it's better to be explicit about your intent, so forcing
the user toround()
before casting when the float has a fractional part is
OK to me.
This would help prevent weird silent conversions such as when you cast to
(int) from user input:$age = $_GET['age']; // '25.75'
$x = (int) $foo; // I'd expect a warning, not a silent conversion to 25— Benjamin
As Rowan said explicit casts are already very fuzzy and should be handled
globally, although I don't agree that they should be changed.
An explicit cast is a choice to force the value to a given type, and many
cases are somewhat reasonable
(e.g. (array) 5 giving array(1) { [0]=> int(5) }), there are IMHO only two
types of blatant bogus type casts which are array being casted to string,
and array/objects being casted to int/float.
And by the looks of it these casts were added because of the usage of the
strict_type declare, which encourages the usage of explicit cast despite
them leading to less type safe code.
This proposal is one of the stepping stones needed to make the strict_type
declare obsolete by converging the behaviour of the coercive typing mode to
the strict type one.
The more I think about it, the more I think it's just a bandaid on some of
the suboptimal behaviour PHP traditionally had.
However, many of these have been somewhat fixed in PHP 8, the two major
ones are systematic TypeErrors for internal functions and the other one is
a saner definition of what a numeric string is.
There are currently 3 remaining reasons, at least from my
perspective/knowledge, as to why the strict_type mode is still needed in
PHP 8:
- Internal functions being implicitly nullable, something being
deprecated with Nikita's RFC [1] which is currently passing with flying
colours. - Implicit float to int conversions, which this RFC is trying to address
- Implicit boolean to scalar conversions, something I want to look into
afterwards but it has a larger surface area which needs to be considered
All other implicit conversions, which currently do not warn or error, are
reasonable from my PoV, and if a codebase wants to adhere to strict type
safety rules there are enough different static analysers nowadays to
achieve this, as strict_types does not achieve this but provides a false
sense that it does.
On Thu, Feb 4, 2021 at 7:22 PM Larry Garfield larry@garfieldtech.com
wrote:I get the idea behind your proposal, but equally I'm not convinced this
is
comparable to numeric vs non-numeric or malformed/partially numeric
strings. There isn't any value of the string "foobar" which makes sense
as
an integer. But there is a value for a float which makes sense as an
integer; the integral part. In the float 3.81232 the integral portion 3
is
completely unambiguous. It's not like it would make just as much sense
to
interpret it as any other arbitrary integer value.Except that example is ambiguous. Specifically, which is more logical,
to
truncate it to 3 or round it up to 4? It probably depends heavily on
your
context. Implicitly doing one or the other can result in surprises.I disagree this is ambiguous. The integral portion of a float is what it
is, any notion of rounding it up is no more relevant here than multiplying
by it 20, calculating it's sin value or anything else you can do with a
number. These are operations you explicitly choose to perform on a scalar.
If you don't care that it has a factional part, then yes it is unambiguous
(which is kind of debatable with the fact floating numbers can be slightly
below the integer value which it should represent when operations have been
done to them).
However, if you don't care then an explicit cast is totally in order to
signal this, as IMHO most people want to have some sort of indication that
they are receiving a float instead of an integer as that can mean there is
an issue prior to receiving it,
as it may need some further processing (be that rounding, increasing
validation on the value received, etc.).
Considering what my long term goal is with this proposal I think I will
change this to a deprecation and write an annexe document which I can refer
to.
The feedback so far has thus been productive.
Best regards,
George P. Banyard
Greetings internal,
I'm proposing a new RFC which would warn when an implicit conversion
from float to int occurs.The draft is currently located on GitHub:
https://github.com/Girgias/float-int-warning/
for ease of commenting/providing changes to it.The official discussion phase wouldn't start before I convert it to
docwiki
and
post it on the wiki, something I'm planning to do next week.Any feedback is appreciated.
Best regards,
George P. Banyard
Hi George,
Thank you for this proposal, I'm all for it, though I'd go one step
further, and actually issue a warning during explicit casting as well:(int) 3.5; //
E_WARNING
(int) round(3.5); // OKIn my experience, it's better to be explicit about your intent, so forcing
the user toround()
before casting when the float has a fractional part is
OK to me.
This would help prevent weird silent conversions such as when you cast to
(int) from user input:$age = $_GET['age']; // '25.75'
$x = (int) $foo; // I'd expect a warning, not a silent conversion to 25— Benjamin
There are legitimate cases for explicitly casting floats to int. For
example floor()
outputs a float, but in the context of the domain I'm
working I might know that the result is never going to exceed a certain
value and want the result explicitly as an int.
(And after checking the manual, I'd also note here that round()
also
returns a float, so how exactly does your example here work? Is it only
OK to explictly cast a float that's the return value of a function? Or
only explictly cast a float if the fractional part is .0? Is that viable
given the "inaccuracy" of floats? Or would it be better for PHP to have
some non-range/accuracy-sensitive representation for integers (and
decimals) here?) (and now we're getting into "why are we still using
floating point math by default in 2021" territory, so I'll stop right here)
AllenJB
PS. Apologies for the dupe to those who did receive my original send,
but I forgot to amend my from address to my subscribed address and as I
recall the list doesn't like list-only replies)
If this were to be done, my gut feeling is a notice would be preferable to
a warning, particularly as there must be many scripts which would suddenly
start churning out warnings for this proposed change which might/probably
ignore lower error levels and emitting a warning for a previously common
script behaviour is quite a significant backwards incompatible change.
The bit which makes me more nervous about the proposed change is your
rationale that implicit float to int conversion dropping the fractional
portion means there is "no way to know if the data provided is erroneous".
I get the idea behind your proposal, but equally I'm not convinced this is
comparable to numeric vs non-numeric or malformed/partially numeric
strings. There isn't any value of the string "foobar" which makes sense as
an integer. But there is a value for a float which makes sense as an
integer; the integral part. In the float 3.81232 the integral portion 3 is
completely unambiguous. It's not like it would make just as much sense to
interpret it as any other arbitrary integer value.
So in these cases, via coercion you're just straightforwardly giving a
valid, unambiguous integer to something which expects an integer. I'd
question why should that raise a warning or TypeError.
In favour of the proposal are a couple of the other issues you mentioned
which mean this would make PHP a bit more consistent all-round...but I'm
not entirely persuaded at this point.
-Dave
Greetings internal,
I'm proposing a new RFC which would warn when an implicit conversion
from float to int occurs.The draft is currently located on GitHub:
https://github.com/Girgias/float-int-warning/
for ease of commenting/providing changes to it.The official discussion phase wouldn't start before I convert it to docwiki
and
post it on the wiki, something I'm planning to do next week.Any feedback is appreciated.
Best regards,
George P. Banyard
If this were to be done, my gut feeling is a notice would be preferable to
a warning, particularly as there must be many scripts which would suddenly
start churning out warnings for this proposed change which might/probably
ignore lower error levels and emitting a warning for a previously common
script behaviour is quite a significant backwards incompatible change.The bit which makes me more nervous about the proposed change is your
rationale that implicit float to int conversion dropping the fractional
portion means there is "no way to know if the data provided is erroneous".I get the idea behind your proposal, but equally I'm not convinced this is
comparable to numeric vs non-numeric or malformed/partially numeric
strings. There isn't any value of the string "foobar" which makes sense as
an integer. But there is a value for a float which makes sense as an
integer; the integral part. In the float 3.81232 the integral portion 3 is
completely unambiguous. It's not like it would make just as much sense to
interpret it as any other arbitrary integer value.
Except that example is ambiguous. Specifically, which is more logical, to truncate it to 3 or round it up to 4? It probably depends heavily on your context. Implicitly doing one or the other can result in surprises.
My main concern is if you're casting floats to ints and the floats are usually ints anyway, and so no error, you may not even realize the error remains for a long time until you suddenly start getting a warning if your incoming data shifts. I have no idea how common that pattern is in practice, though.
--Larry Garfield
Except that example is ambiguous. Specifically, which is more logical,
to truncate it to 3 or round it up to 4? It probably depends heavily on
your context. Implicitly doing one or the other can result in surprises.
I disagree this is ambiguous. The integral portion of a float is what it
is, any notion of rounding it up is no more relevant here than multiplying
by it 20, calculating it's sin value or anything else you can do with a
number. These are operations you explicitly choose to perform on a scalar.
On Thu, Feb 4, 2021 at 7:22 PM Larry Garfield larry@garfieldtech.com
wrote:
If this were to be done, my gut feeling is a notice would be preferable
to
a warning, particularly as there must be many scripts which would
suddenly
start churning out warnings for this proposed change which might/probably
ignore lower error levels and emitting a warning for a previously common
script behaviour is quite a significant backwards incompatible change.The bit which makes me more nervous about the proposed change is your
rationale that implicit float to int conversion dropping the fractional
portion means there is "no way to know if the data provided is
erroneous".I get the idea behind your proposal, but equally I'm not convinced this
is
comparable to numeric vs non-numeric or malformed/partially numeric
strings. There isn't any value of the string "foobar" which makes sense
as
an integer. But there is a value for a float which makes sense as an
integer; the integral part. In the float 3.81232 the integral portion 3
is
completely unambiguous. It's not like it would make just as much sense to
interpret it as any other arbitrary integer value.Except that example is ambiguous. Specifically, which is more logical, to
truncate it to 3 or round it up to 4? It probably depends heavily on your
context. Implicitly doing one or the other can result in surprises.My main concern is if you're casting floats to ints and the floats are
usually ints anyway, and so no error, you may not even realize the error
remains for a long time until you suddenly start getting a warning if your
incoming data shifts. I have no idea how common that pattern is in
practice, though.--Larry Garfield
--
To unsubscribe, visit: https://www.php.net/unsub.php