Hello internals,
Many, many people start their files fairly religiously:
<?php declare(strict_types=1);
and I say "religiously" because from talking to people in real life,
reddit, workplaces, etc, very few php programmers actually know what
this does but do it nonetheless. I've heard everything from "it
enables type hints" to "it makes it so that I know I got my class
instead of an int" to getting it right, but thinking it applies to
code calling from another file, and not them calling code.
Granted, I haven't done a scientific poll (though I did one on Reddit
this morning for giggles to ensure it isn't just the people I know).
One thing is clear is that "strict types" may be a bit of poor word
choice and gives people a false sense of security that it is "safe" or
"more correct" when this obviously isn't true. Thus, I'd like to
propose, for PHP 9, simply renaming it from strict_types to
scalar_type_coercion and flipping the value:
<?php declare(strict_types=1);
to
<?php declare(scalar_type_coercion=0);
Perhaps it might even be worth adding a secondary vote to flip the
default, such that if you want to "old" behavior back:
<?php declare(scalar_type_coercion=1);
I'm not attached to the name "scalar_type_coercion" by any stretch,
but I do feel that "strict_types" gives people the wrong idea about
what is going on when they enable it and renaming it to something more
clear might be helpful.
What are your thoughts?
PS. Personally, I would rather unify non-strict and strict in some way
that makes sense ... so, that route sounds nice too.
Robert Landers
Software Engineer
Utrecht NL
Hi,
One thing is clear is that "strict types" may be a bit of poor word
choice and gives people a false sense of security that it is "safe" or
"more correct" when this obviously isn't true. Thus, I'd like to
propose, for PHP 9, simply renaming it from strict_types to
scalar_type_coercion and flipping the value:<?php declare(strict_types=1);
to
<?php declare(scalar_type_coercion=0);
This not better. Even with declare(scalar_type_coercion=0)
, there will be scalar type conversions between string and int/float when you add numeric strings or when you concatenate a string with an int.
IMO, the real problem with the current name, is that there is no clue that this directive is specifically about arguments and return values in function/method calls.
Perhaps it might even be worth adding a secondary vote to flip the
default, such that if you want to "old" behavior back:<?php declare(scalar_type_coercion=1);
That would force to edit thousands of files, ... for exactly zero gain. Have you heard about the Red Queen's race?
Moreover, there are many places where it is not possible to add such a declaration. For instance, array_map(...)
, etc., always use strict_types=0
when invoking the callback. Changing that would also be a big BC break.
—Claude
Hi,
One thing is clear is that "strict types" may be a bit of poor word
choice and gives people a false sense of security that it is "safe" or
"more correct" when this obviously isn't true. Thus, I'd like to
propose, for PHP 9, simply renaming it from strict_types to
scalar_type_coercion and flipping the value:<?php declare(strict_types=1);
to
<?php declare(scalar_type_coercion=0);
This not better. Even with
declare(scalar_type_coercion=0)
, there will be scalar type conversions between string and int/float when you add numeric strings or when you concatenate a string with an int.
This is a really good point and worth thinking about. I kinda like
Rowan's suggestion of scalar_args with a usage of string values
instead of integers.
IMO, the real problem with the current name, is that there is no clue that this directive is specifically about arguments and return values in function/method calls.
Yes. This is kinda what I was hoping to address, but like you said,
the name I suggested didn't really capture the semantics either. :D
Perhaps it might even be worth adding a secondary vote to flip the
default, such that if you want to "old" behavior back:<?php declare(scalar_type_coercion=1);
That would force to edit thousands of files, ... for exactly zero gain. Have you heard about the Red Queen's race?
This is a pretty simple search-and-replace, so I don't think it would
be hard to update. That being said, there still needs to be a
deprecation strategy that makes sense. As to it being "zero gain,"
words have meaning and choosing the right ones (even if it is years
later) can sometimes be completely worth it and even have monetary
gains.
Moreover, there are many places where it is not possible to add such a declaration. For instance,
array_map(...)
, etc., always usestrict_types=0
when invoking the callback. Changing that would also be a big BC break.—Claude
Robert Landers
Software Engineer
Utrecht NL
One thing is clear is that "strict types" may be a bit of poor word
choice and gives people a false sense of security that it is "safe" or
"more correct" when this obviously isn't true.
I totally agree with this sentiment. I don't think it should be called
"strict", and I don't think it should be "on or off" either.
If I had a time machine, I'd propose something like:
declare(scalar_args=coerce);
declare(scalar_args=error);
Or perhaps:
declare(coerce_scalar_args=if_safe);
declare(coerce_scalar_args=never);
But...
Thus, I'd like to propose, for PHP 9, simply renaming it...
I'm not sure the pain is worth it. We'd have to introduce support
gradually, probably not phasing out the old name until 10.0 at the
earliest, so you'd just end up with more confusion with people not
understanding if they were the same thing, which one to use in which
version, etc.
Perhaps it might even be worth adding a secondary vote to flip the
default, such that if you want to "old" behavior back
You're falling into the same trap you're describing: assuming that
strict_types=0 is an "older" mode, or a "worse" one. Both modes were
introduced at exactly the same time, as a direct choice to users between
two different styles, which had been proposed in competing RFCs.
Changing the default, and the name, but keeping the same behaviour,
would just be a huge mess.
Personally, I would rather unify non-strict and strict in some way that makes sense
I think this is where we should be focussing our attention. We've had
some great RFCs over the last few years tightening up some of the
weirder excesses of PHP's type juggling system.
With a tight enough definition of "numeric string" and other coercible
values, I think "mode 0" could be strict enough that "mode 1" wouldn't
feel so necessary.
Then again, I was broadly in favour of the original coercive-only
proposal for scalar type parameters, and there are those who felt
strongly on the other side. The debate was extremely heated, and I'm not
in a hurry to reopen it.
Regards,
--
Rowan Tommins
[IMSoP]
On Tue, Jun 18, 2024 at 10:46 PM Rowan Tommins [IMSoP]
imsop.php@rwec.co.uk wrote:
One thing is clear is that "strict types" may be a bit of poor word
choice and gives people a false sense of security that it is "safe" or
"more correct" when this obviously isn't true.I totally agree with this sentiment. I don't think it should be called "strict", and I don't think it should be "on or off" either.
If I had a time machine, I'd propose something like:
declare(scalar_args=coerce);
declare(scalar_args=error);Or perhaps:
declare(coerce_scalar_args=if_safe);
declare(coerce_scalar_args=never);
This is nice. I like it :)
But...
Thus, I'd like to propose, for PHP 9, simply renaming it...
I'm not sure the pain is worth it. We'd have to introduce support gradually, probably not phasing out the old name until 10.0 at the earliest, so you'd just end up with more confusion with people not understanding if they were the same thing, which one to use in which version, etc.
I honestly don't know how the deprecation would work, or what makes
sense. Supporting both makes sense and as long as the behavior stays
exactly the same, and they are both set to the same thing, that would
probably be fine for awhile. Is it confusing... I wouldn't find it
confusing unless I was working on something that supported <9 and >9
and eventually 8.x will EoL and then it won't be so confusing anymore.
Perhaps it might even be worth adding a secondary vote to flip the
default, such that if you want to "old" behavior backYou're falling into the same trap you're describing: assuming that strict_types=0 is an "older" mode, or a "worse" one. Both modes were introduced at exactly the same time, as a direct choice to users between two different styles, which had been proposed in competing RFCs.
Changing the default, and the name, but keeping the same behaviour, would just be a huge mess.
Personally, I would rather unify non-strict and strict in some way that makes sense
I think this is where we should be focussing our attention. We've had some great RFCs over the last few years tightening up some of the weirder excesses of PHP's type juggling system.
I've been mulling this around in my head last night and this morning.
I think I have something that makes sense, based mostly on information
loss. Essentially, an int could become a float (within some limits),
but a float can only become an int if it is an int itself. The same
concept of a string, where "123test" couldn't become a number because
"test" would be lost. Booleans are tricky, but I'd be inclined to keep
it as-is; otherwise, the BC break would be unbearable.
I think something like that would logically make sense. Whether or not
it would be feasible to implement in a performant way, I have no idea
(but it would be nice to clean up that area of the C code since it's a
bit of a tangle, IMHO). Interestingly, we could still do normal
coercion but just warn when there is information loss. Then, people
can ignore/catch those warnings and do whatever they want with them.
If information loss is what you want and you want to get rid of the
warning, you can simply add an explicit cast, but it would be nice
also to adjust casting so you can do
(int|null) $value; // or (?int) $value
so null won't be cast to zero. But that should probably be a totally
separate RFC and out of scope atm.
With a tight enough definition of "numeric string" and other coercible values, I think "mode 0" could be strict enough that "mode 1" wouldn't feel so necessary.
Then again, I was broadly in favour of the original coercive-only proposal for scalar type parameters, and there are those who felt strongly on the other side. The debate was extremely heated, and I'm not in a hurry to reopen it.
Regards,
--
Rowan Tommins
[IMSoP]
Robert Landers
Software Engineer
Utrecht NL
Essentially, an int could become a float (within some limits),
but a float can only become an int if it is an int itself. The same
concept of a string, where "123test" couldn't become a number because
"test" would be lost.
Both of these are already covered, at least as far as parameter/return
types, which is what "strict_types" controls...
'123test' is rejected, not coerced to int, as of 8.0: https://3v4l.org/nvbML
Losing precision on a float-to-int is deprecated, so will presumably
error as of 9.0: https://3v4l.org/vvD2e
--
Rowan Tommins
[IMSoP]
Hello internals,
Many, many people start their files fairly religiously:
<?php declare(strict_types=1);
and I say "religiously" because from talking to people in real life,
reddit, workplaces, etc, very few php programmers actually know what
this does but do it nonetheless.
I think there's almost certainly a degree of truth, not just in PHP but
programming in general, in the idea that there are many people who will
blindly follow a convention for no better reason they once heard someone
they considered more senior than themselves say the words "best practice"
But I don't think the meaning of strict_types in PHP is unclear. It's right
there in the manual
https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict
If anyone is daft enough to use a language feature without referencing what
it means or what it does, let them clean up any problems which arise for
them as a result.
If I were to support any change to how this feature works for PHP 9, I
think it would be providing a mechanism to enable it for all files at once,
maybe either via a .ini setting such as strict_types_default=1 or a new
declare which applies to all files included or autoloaded from that point
on, i.e. a declare that could be used as the first line of an entrypoint
script to make all files in a project have strict typing mode
enabled/disabled (unless a particular file overrides for its own scope with
its own declare).
Changing the name to anything other than what it is now, with or without
flipping the value, just seems like a major BC headache for no gain.
-Dave
Hello internals,
Many, many people start their files fairly religiously:
<?php declare(strict_types=1);
and I say "religiously" because from talking to people in real life,
reddit, workplaces, etc, very few php programmers actually know what
this does but do it nonetheless.I think there's almost certainly a degree of truth, not just in PHP but programming in general, in the idea that there are many people who will blindly follow a convention for no better reason they once heard someone they considered more senior than themselves say the words "best practice"
But I don't think the meaning of strict_types in PHP is unclear. It's right there in the manual https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict
If anyone is daft enough to use a language feature without referencing what it means or what it does, let them clean up any problems which arise for them as a result.
The problem isn't so much this, but in that it has become a dogma to
"have working types" and trying to explain why they do or do not
need/want it in the current context becomes a hopeless argument
because you are attacking their world-view instead of having an
academic argument.
If I were to support any change to how this feature works for PHP 9, I think it would be providing a mechanism to enable it for all files at once, maybe either via a .ini setting such as strict_types_default=1 or a new declare which applies to all files included or autoloaded from that point on, i.e. a declare that could be used as the first line of an entrypoint script to make all files in a project have strict typing mode enabled/disabled (unless a particular file overrides for its own scope with its own declare).
I've explicitly written code without strict types because, in that
context, I want coercion (mostly when dealing with env vars)
surrounded by files with strict types enabled. Multiple steps would
have to be taken to make this possible (i.e., requiring the setting on
every file, whether off or on), negating the entire feature of having
it set globally. There may be a path where this makes sense, but I
don't think we can get there from here.
Changing the name to anything other than what it is now, with or without flipping the value, just seems like a major BC headache for no gain.
-Dave
Robert Landers
Software Engineer
Utrecht NL
The problem isn't so much this, but in that it has become a dogma to
"have working types" and trying to explain why they do or do not
need/want it in the current context becomes a hopeless argument
because you are attacking their world-view instead of having an
academic argument
If the feature was an RFC being introduced today and you were suggesting
using a better, more descriptive name than strict_types I'd agree.
But it is what it is, it's already in the language, it's already very
widely used and changing the name now won't solve any problem, to whatever
extent that problem exists (which I honestly don't think is very big), of
there being a cohort of users who rigidly stick to using this declare
because they've been told they should always do so, or because they have a
dogmatic opinion about how PHP's type system should work in their ideal of
the language.
Both those groups would continue to use the directive everywhere,
regardless of what it was called. And it's their code, their right. No one
is under any obligation to engage in an academic argument to justify design
decisions in code they own.
-Dave
Hi David, Robert,
wt., 18 cze 2024 o 23:12 David Gebler davidgebler@gmail.com napisał(a):
...
If I were to support any change to how this feature works for PHP 9, I
think it would be providing a mechanism to enable it for all files at once,
maybe either via a .ini setting such as strict_types_default=1 or a new
declare which applies to all files included or autoloaded from that point
on, i.e. a declare that could be used as the first line of an entrypoint
script to make all files in a project have strict typing mode
enabled/disabled (unless a particular file overrides for its own scope with
its own declare).Changing the name to anything other than what it is now, with or without
flipping the value, just seems like a major BC headache for no gain.
I share a similar opinion here.
I'd also rather see a proposal that enables setting the declares outside of
PHP files as this is mostly the same line for every file in most codebases
I work with.
name it .phpdeclare
in the execution directory or places where certain
PHP files are read by the PHP interpreter, whatever
# Global default directives
[*.php]
strict_types = 1
ticks = 0
encoding = UTF-8
# Directives for specific directories
[src/*.php]
strict_types = 1
[tests/*.php]
strict_types = 0
# Directives for specific files
[scripts/setup.php]
strict_types = 1
ticks = 1
Just an example, shoving some declares can be set using glob-like patterns
or specific files.
I see potential in this kind of declaring these directives for future
extensions.
This is something I'd love to consider instead of just renaming things we
already have.
Cheers,
Michał Marcin Brzuchalski
Hello internals,
Many, many people start their files fairly religiously:
<?php declare(strict_types=1);
and I say "religiously" because from talking to people in real life,
reddit, workplaces, etc, very few php programmers actually know what
this does but do it nonetheless.I think there's almost certainly a degree of truth, not just in PHP but programming in general, in the idea that there are many people who will blindly follow a convention for no better reason they once heard someone they considered more senior than themselves say the words "best practice"
There is a notable term for that: "Cargo Cult Programming":
https://en.wikipedia.org/wiki/Cargo_cult_programming https://en.wikipedia.org/wiki/Cargo_cult_programming
#fwiw
-Mike
Hello internals,
[...]
What are your thoughts?
As self-proclaimed leading expert on PHP type juggling.
That it is a terrible idea with no gains whatsoever.
Renaming the declare statement does not improve the situation.
PS. Personally, I would rather unify non-strict and strict in some way
that makes sense ... so, that route sounds nice too.
See my old meta RFC: https://github.com/Girgias/unify-typing-modes-rfc
It is a somewhat known hot take from mine that I think the strict_type declare statement was a mistake. [1]
Mainly because it affects barely nothing in regard to the engine.
I have written/co-authored multiple RFCs over the years to make the default coercion mode less whack. [2][3][4][5][6][7]
And my container/offset RFC is in the same vein [8] which lead me into a different rabbit hole then the one I was expecting to explore which is addressing PHP's weird comparison semantics. [9]
Therefore, I would rather we focus on actually fixing PHP's semantics, than arguing about changing the name of something that shouldn't really exist in the first place.
Best regards,
Gina P. Banyard
[1] Slide 68 of my PHP UK talk "PHP's Type System Dissected": https://gpb.moe/doc/slides/PHP_Type_System_Talk_PHPUK2023.pdf
[2] https://wiki.php.net/rfc/saner-numeric-strings
[3] https://wiki.php.net/rfc/implicit-float-int-deprecate
[4] https://wiki.php.net/rfc/saner-inc-dec-operators
[5] https://wiki.php.net/rfc/locale_independent_float_to_string
[6] https://wiki.php.net/rfc/exit-as-function
[7] https://wiki.php.net/rfc/deprecate-boolean-string-coercion
[8] https://github.com/Girgias/php-rfcs/blob/master/container-offset-behaviour.md
[9] https://github.com/Girgias/php-rfcs/blob/master/comparison-equality-semantics.md
On Tuesday, 18 June 2024 at 17:37, Robert Landers
landers.robert@gmail.com wrote:Hello internals,
[...]
What are your thoughts?
As self-proclaimed leading expert on PHP type juggling.
That it is a terrible idea with no gains whatsoever.
Renaming the declare statement does not improve the situation.PS. Personally, I would rather unify non-strict and strict in some way
that makes sense ... so, that route sounds nice too.See my old meta RFC: https://github.com/Girgias/unify-typing-modes-rfc
It is a somewhat known hot take from mine that I think the strict_type
declare statement was a mistake. [1]
Mainly because it affects barely nothing in regard to the engine.I have written/co-authored multiple RFCs over the years to make the
default coercion mode less whack. [2][3][4][5][6][7]
And my container/offset RFC is in the same vein [8] which lead me into
a different rabbit hole then the one I was expecting to explore which
is addressing PHP's weird comparison semantics. [9]Therefore, I would rather we focus on actually fixing PHP's
semantics, than arguing about changing the name of something that
shouldn't really exist in the first place.Best regards,
Gina P. Banyard
[1] Slide 68 of my PHP UK talk "PHP's Type System Dissected":
https://gpb.moe/doc/slides/PHP_Type_System_Talk_PHPUK2023.pdf
[2] https://wiki.php.net/rfc/saner-numeric-strings
[3] https://wiki.php.net/rfc/implicit-float-int-deprecate
[4] https://wiki.php.net/rfc/saner-inc-dec-operators
[5] https://wiki.php.net/rfc/locale_independent_float_to_string
[6] https://wiki.php.net/rfc/exit-as-function
[7] https://wiki.php.net/rfc/deprecate-boolean-string-coercion
[8]
https://github.com/Girgias/php-rfcs/blob/master/container-offset-behaviour.md
[9]
https://github.com/Girgias/php-rfcs/blob/master/comparison-equality-semantics.md
What Gina said. Renaming the declare key would involve changing literally millions of files, even if it's over the course of a decade, for little if any benefit.
Reducing the delta between weak mode and strict mode to the point that it makes little difference (by making the PHP type juggling system less nonsensical and random) is a much more achievable goal, and actually has value to justify the effort (both for Internals and for people updating their code).
Also, as someone who does put every file into strict mode as a matter of course, and appreciates the many languages that do not even have a concept of non-strict mode (like Go or Rust), I really don't appreciate the backhanded comments in this thread about people who, you know, care about type safety. (Something that weak mode, when it was introduced in PHP 7, only marginally provided if at all.) Strict mode prevents bugs, full stop, and we should not fault anyone for applying that bug-stopper tool liberally.
--Larry Garfield
Am 19.06.2024 um 17:34 schrieb Larry Garfield:
Also, as someone who does put every file into strict mode as a matter of course, and appreciates the many languages that do not even have a concept of non-strict mode (like Go or Rust), I really don't appreciate the backhanded comments in this thread about people who, you know, care about type safety. (Something that weak mode, when it was introduced in PHP 7, only marginally provided if at all.) Strict mode prevents bugs, full stop, and we should not fault anyone for applying that bug-stopper tool liberally.
What Larry and Gina said.
Am 19.06.2024 um 17:34 schrieb Larry Garfield:
Also, as someone who does put every file into strict mode as a matter of course, and appreciates the many languages that do not even have a concept of non-strict mode (like Go or Rust), I really don't appreciate the backhanded comments in this thread about people who, you know, care about type safety. (Something that weak mode, when it was introduced in PHP 7, only marginally provided if at all.) Strict mode prevents bugs, full stop, and we should not fault anyone for applying that bug-stopper tool liberally.
What Larry and Gina said.
Strange, I don't have an email from Larry! But I suspect it will show
up eventually... I look forward to it!
I'll go ahead and risk an out-of-context reply, but FWIW, it goes both
ways :) People get irrational about this topic, either for-or-against.
In any case, there is not any "type safety" in PHP because PHP doesn't
know something is the wrong type until runtime. Further, it clearly
doesn't stop bugs, otherwise we'd all be out of a job by now.
Robert Landers
Software Engineer
Utrecht NL
Also, as someone who does put every file into strict mode as a matter of
course, and appreciates the many languages that do not even have a
concept of non-strict mode (like Go or Rust), I really don't appreciate
the backhanded comments in this thread about people who, you know, care
about type safety. (Something that weak mode, when it was introduced in
PHP 7, only marginally provided if at all.) Strict mode prevents bugs,
full stop, and we should not fault anyone for applying that bug-stopper
tool liberally.
Used correctly, it absolutely does. Used incorrectly, it can actually
end up hiding errors.
I've seen lots of cases where code like this:
some_function_expecting_int($_GET['foo']);
Gets changed to this:
declare(strict_types=1);
some_function_expecting_int( (int)$_GET['foo'] );
Even in PHP 7.0, the first version is actually stricter than the
second, because explicit casts never fail, but parameter coercion (mode
0) always failed for strings like "hello"; as of 8.0, it also fails for
strings like "123foo" and "".
And this is exactly the kind of code that coercive type hints were
intended for - HTTP is a text-based protocol, so most PHP applications
are dealing with string input and output all the time.
One of the things the language badly needs, and I have been trying to
come up with a proposal for, is strict type casts, so that this code can
actually be written safely but still concisely.
Regards,
--
Rowan Tommins
[IMSoP]
On Thu, Jun 20, 2024 at 11:54 PM Rowan Tommins [IMSoP] imsop.php@rwec.co.uk
wrote:
Also, as someone who does put every file into strict mode as a matter of
course, and appreciates the many languages that do not even have a
concept of non-strict mode (like Go or Rust), I really don't appreciate
the backhanded comments in this thread about people who, you know, care
about type safety. (Something that weak mode, when it was introduced in
PHP 7, only marginally provided if at all.) Strict mode prevents bugs,
full stop, and we should not fault anyone for applying that bug-stopper
tool liberally.
Hey Rowan,
What Gina, Larry and Sebastian said.
My $0.02 is
-
typing "declare(strict_types=1);" is already cumbersome enough, we don't
need to be adding more words and complexity to it -
adding the word "coerce" or "coercion" to a thing is really not good
from a DX (developer experience) perspective. It will not add clarity it
will add confusion... "What is this coersion thing I've never heard of" -
remember who the target audience is.. Rust and Golang are not
beginner-friendly or entry-level languages, so the fact you're even using
Rust means you know what you're doing and likely know what coersion is
3.1 PHP's strength is that it's beginner friendly and by that I mean just
remember a significant portion of our userbase are Wordpress developers
(and Drupal / Magento alike) .. and many WP devs won't have even heard of
Dependency Injection before nevermind the complexities of type coersion, so
we need to keep things simple as possible at all times
- I think the solution you're looking here for is better education to
the end-users, on what the implications of X or Y are .. rather than
changing the language itself .. so the merits of your proposal are good, in
that it helps the end-user understand the system better .. it's just the
solution you're proposing here just isn't it (so far).
Used correctly, it absolutely does. Used incorrectly, it can actually end
up hiding errors.
I've seen lots of cases where code like this:
some_function_expecting_int($_GET['foo']);
Gets changed to this:
declare(strict_types=1);
some_function_expecting_int( (int)$_GET['foo'] );Even in PHP 7.0, the first version is actually stricter than the second,
because explicit casts never fail, but parameter coercion (mode 0) always
failed for strings like "hello"; as of 8.0, it also fails for strings like
"123foo" and "".And this is exactly the kind of code that coercive type hints were
intended for - HTTP is a text-based protocol, so most PHP applications are
dealing with string input and output all the time.One of the things the language badly needs, and I have been trying to come
up with a proposal for, is strict type casts, so that this code can
actually be written safely but still concisely.Regards,
--
Rowan Tommins
[IMSoP]
On Thu, Jun 20, 2024 at 11:54 PM Rowan Tommins [IMSoP] <
imsop.php@rwec.co.uk> wrote:Also, as someone who does put every file into strict mode as a matter of
course, and appreciates the many languages that do not even have a
concept of non-strict mode (like Go or Rust), I really don't appreciate
the backhanded comments in this thread about people who, you know, care
about type safety. (Something that weak mode, when it was introduced in
PHP 7, only marginally provided if at all.) Strict mode prevents bugs,
full stop, and we should not fault anyone for applying that bug-stopper
tool liberally.Hey Rowan,
I meant Hey Robert, but half replying to Rowan's suggestions too.
What Gina, Larry and Sebastian said.
My $0.02 is
typing "declare(strict_types=1);" is already cumbersome enough, we
don't need to be adding more words and complexity to itadding the word "coerce" or "coercion" to a thing is really not good
from a DX (developer experience) perspective. It will not add clarity it
will add confusion... "What is this coersion thing I've never heard of"remember who the target audience is.. Rust and Golang are not
beginner-friendly or entry-level languages, so the fact you're even using
Rust means you know what you're doing and likely know what coersion is3.1 PHP's strength is that it's beginner friendly and by that I mean just
remember a significant portion of our userbase are Wordpress developers
(and Drupal / Magento alike) .. and many WP devs won't have even heard of
Dependency Injection before nevermind the complexities of type coersion, so
we need to keep things simple as possible at all times
- I think the solution you're looking here for is better education to
the end-users, on what the implications of X or Y are .. rather than
changing the language itself .. so the merits of your proposal are good, in
that it helps the end-user understand the system better .. it's just the
solution you're proposing here just isn't it (so far).Used correctly, it absolutely does. Used incorrectly, it can actually end
up hiding errors.
I've seen lots of cases where code like this:
some_function_expecting_int($_GET['foo']);
Gets changed to this:
declare(strict_types=1);
some_function_expecting_int( (int)$_GET['foo'] );Even in PHP 7.0, the first version is actually stricter than the
second, because explicit casts never fail, but parameter coercion (mode 0)
always failed for strings like "hello"; as of 8.0, it also fails for
strings like "123foo" and "".And this is exactly the kind of code that coercive type hints were
intended for - HTTP is a text-based protocol, so most PHP applications are
dealing with string input and output all the time.One of the things the language badly needs, and I have been trying to
come up with a proposal for, is strict type casts, so that this code can
actually be written safely but still concisely.Regards,
--
Rowan Tommins
[IMSoP]
On Fri, Jun 21, 2024 at 12:54 AM Rowan Tommins [IMSoP]
imsop.php@rwec.co.uk wrote:
Also, as someone who does put every file into strict mode as a matter of
course, and appreciates the many languages that do not even have a
concept of non-strict mode (like Go or Rust), I really don't appreciate
the backhanded comments in this thread about people who, you know, care
about type safety. (Something that weak mode, when it was introduced in
PHP 7, only marginally provided if at all.) Strict mode prevents bugs,
full stop, and we should not fault anyone for applying that bug-stopper
tool liberally.Used correctly, it absolutely does. Used incorrectly, it can actually end up hiding errors.
I've seen lots of cases where code like this:
some_function_expecting_int($_GET['foo']);
Gets changed to this:
declare(strict_types=1);
some_function_expecting_int( (int)$_GET['foo'] );Even in PHP 7.0, the first version is actually stricter than the second, because explicit casts never fail, but parameter coercion (mode 0) always failed for strings like "hello"; as of 8.0, it also fails for strings like "123foo" and "".
And this is exactly the kind of code that coercive type hints were intended for - HTTP is a text-based protocol, so most PHP applications are dealing with string input and output all the time.
One of the things the language badly needs, and I have been trying to come up with a proposal for, is strict type casts, so that this code can actually be written safely but still concisely.
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:
some_function_expecting_int($_GET['foo'] as ?int);
would be super nice. I think it just depends on if we wanted to go the
C# route (where "as" => null if not an int/null) or throw an error if
it isn't one of those types. The more I think about it, I kinda like
the C# way, but I feel like the error way is more idiomatic for PHP,
which is much stricter on nullables.
HTTP is a text-based protocol, so most PHP applications are dealing with string input and output all the time.
In PHP, pretty much everything starts as a string because everything
starts as a series of bytes, which can only be represented as a string
in PHP. There's always something that has to convert those bytes into
more useful information (whether that string is human-readable or
not). Sometimes, a PHP extension will do it for you, and sometimes, it
won't, and you have to do it yourself. Doing it yourself is usually
where you don't want strict types (if you trust coercion to behave as
documented) or want more control, so you turn on strict types. There's
quite a lot of footguns with strict types (like the one you
mentioned), but also others, particularly in library code that accepts
callbacks.
Robert Landers
Software Engineer
Utrecht NL
Le 21/06/2024 à 14:27, Robert Landers a écrit :
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:some_function_expecting_int($_GET['foo'] as ?int);
And how about:
some_function_expecting_int(\intval($_GET['foo']));
And moreover, I'd write something like this, but:
function validate_int(mixed $value): int {
if (null === $value || '' === $value) {
return null;
}
if (\is_int($value)) {
return $value;
}
if (\is_string($value) && \ctype_digit($value)) {
return \intval($value);
}
throw new \InvalidArgumentException("What what!");
}
some_function_expecting_int(validate_int($_GET['foo'] ?? null));
But the example might be erroneous, I see your point, nevertheless
making coercion explicit doesn't seem really relevant to me, the one
point I like in your syntax would be null handling.
--
Pierre
Le 21/06/2024 à 14:27, Robert Landers a écrit :
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:some_function_expecting_int($_GET['foo'] as ?int);
I've started drafting a proposal for strict casts - independent of the pattern matching effort, but might be combinable - but the devil's in the details of exactly when the cast should fail, and what should happen when it does.
For instance, should cast('abc' as ?int) fail, or default to null? Do we need different syntax for both? I have some thoughts, but haven't quite settled on a full proposal yet.
And how about:
some_function_expecting_int(\intval($_GET['foo']));
intval($foo) and (int)$foo do exactly the same thing; they're basically just different syntax.
And moreover, I'd write something like this, but:
function validate_int(mixed $value): int { ...
Which is why I included the word concise: it shouldn't be necessary for every user to write or install a custom function for such a common requirement.
Regards,
Rowan Tommins
[IMSoP]
On Fri, Jun 21, 2024 at 4:50 PM Rowan Tommins [IMSoP]
imsop.php@rwec.co.uk wrote:
Le 21/06/2024 à 14:27, Robert Landers a écrit :
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:some_function_expecting_int($_GET['foo'] as ?int);
I've started drafting a proposal for strict casts - independent of the pattern matching effort, but might be combinable - but the devil's in the details of exactly when the cast should fail, and what should happen when it does.
For instance, should cast('abc' as ?int) fail, or default to null? Do we need different syntax for both? I have some thoughts, but haven't quite settled on a full proposal yet.
I know we have different opinions about many things, but I'd actually
love to help if you'd want it. I think our different opinions might
make it better. :)
I vaguely remember our last conversation about this and I kinda liked
your 'catch' thing. IIRC, it looked something like:
'abc' as ?int otherwise false;
or something (pretty sure it wasn't "otherwise") where if it wasn't an
int|null, it would fall back to false. If there wasn't a fallback, it
was a TypeError or something?
One thing nice about "as" is that having typed variables becomes much
more simpler to implement (if anyone wanted to implement it) even as a
transpilation step:
int $x = 5;
$x += "10"; // type error
gets transpiled to:
$x = 5 as int;
$x += "10" as int;
Interesting stuff.
And how about:
some_function_expecting_int(\intval($_GET['foo']));
intval($foo) and (int)$foo do exactly the same thing; they're basically just different syntax.
And moreover, I'd write something like this, but:
function validate_int(mixed $value): int { ...
Which is why I included the word concise: it shouldn't be necessary for every user to write or install a custom function for such a common requirement.
Regards,
Rowan Tommins
[IMSoP]
Robert Landers
Software Engineer
Utrecht NL
Le 21/06/2024 à 14:27, Robert Landers a écrit :
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:some_function_expecting_int($_GET['foo'] as ?int);
And how about:
some_function_expecting_int(\intval($_GET['foo']));
And moreover, I'd write something like this, but:
function validate_int(mixed $value): int {
if (null === $value || '' === $value) {
return null;
}
if (\is_int($value)) {
return $value;
}
if (\is_string($value) && \ctype_digit($value)) {
return \intval($value);
}
throw new \InvalidArgumentException("What what!");
}some_function_expecting_int(validate_int($_GET['foo'] ?? null));
But the example might be erroneous, I see your point, nevertheless making coercion explicit doesn't seem really relevant to me, the one point I like in your syntax would be null handling.
--
Pierre
Or... you could just turn off strict types instead of reinventing
coercion that isn't nearly as well documented as the built-in
coercion.
Robert Landers
Software Engineer
Utrecht NL
Le 21/06/2024 à 15:57, Robert Landers a écrit :
Le 21/06/2024 à 14:27, Robert Landers a écrit :
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:some_function_expecting_int($_GET['foo'] as ?int);
And how about:
some_function_expecting_int(\intval($_GET['foo']));
And moreover, I'd write something like this, but:
function validate_int(mixed $value): int {
if (null === $value || '' === $value) {
return null;
}
if (\is_int($value)) {
return $value;
}
if (\is_string($value) && \ctype_digit($value)) {
return \intval($value);
}
throw new \InvalidArgumentException("What what!");
}some_function_expecting_int(validate_int($_GET['foo'] ?? null));
But the example might be erroneous, I see your point, nevertheless making coercion explicit doesn't seem really relevant to me, the one point I like in your syntax would be null handling.
--
Pierre
Or... you could just turn off strict types instead of reinventing
coercion that isn't nearly as well documented as the built-in
coercion.
That was one of my points actually.
I don't see the use of a syntax such as $foo as ?int
since all
existing types of coercion are already possible via the cast syntax
(please correct me if I'm wrong).
In the previous message proposal, the only neat addition was the null
handling (that's said, that's a really cool point). But cast syntax
(int) $foo
is really equivalent to $foo as int
in terme of concision
(less than 2 chars diff).
In almost every case you would need coercion you also need validation,
and validation is not something that's possible with a neat syntax, at
least not this one, because validation is a business matter, not really
a technical one.
Regards,
--
Pierre
Le 21/06/2024 à 15:57, Robert Landers a écrit :
Le 21/06/2024 à 14:27, Robert Landers a écrit :
This is why I wanted to work on "as" part of the pattern matching. It
isn't clear what will happen with the actual pattern matching RFC
(yet), but being able to do:some_function_expecting_int($_GET['foo'] as ?int);
And how about:
some_function_expecting_int(\intval($_GET['foo']));
And moreover, I'd write something like this, but:
function validate_int(mixed $value): int {
if (null === $value || '' === $value) {
return null;
}
if (\is_int($value)) {
return $value;
}
if (\is_string($value) && \ctype_digit($value)) {
return \intval($value);
}
throw new \InvalidArgumentException("What what!");
}some_function_expecting_int(validate_int($_GET['foo'] ?? null));
But the example might be erroneous, I see your point, nevertheless making coercion explicit doesn't seem really relevant to me, the one point I like in your syntax would be null handling.
--
Pierre
Or... you could just turn off strict types instead of reinventing
coercion that isn't nearly as well documented as the built-in
coercion.That was one of my points actually.
I don't see the use of a syntax such as
$foo as ?int
since all
existing types of coercion are already possible via the cast syntax
(please correct me if I'm wrong).In the previous message proposal, the only neat addition was the null
handling (that's said, that's a really cool point). But cast syntax
(int) $foo
is really equivalent to$foo as int
in terme of concision
(less than 2 chars diff).
Well, $foo as int doesn't exist (yet), so there's no telling what it
will be the same as.
In almost every case you would need coercion you also need validation,
and validation is not something that's possible with a neat syntax, at
least not this one, because validation is a business matter, not really
a technical one.
That may be true, but isn't always true. Other than how it is
represented in memory, is there any difference between "123", 123, and
123.0? That's what coercion does, it makes it so that the actual
representation doesn't matter. The only thing you really have to worry
about are the edge cases (for which there are many, but that number
has slowly gone down over the years and none of the remaining ones are
truly surprising, IMHO).
And if you are just going to cast a float/string to an int anyway, you
still have edge cases (null, no warning about information loss, etc)
to handle.
Regards,
--
Pierre
I don't see the use of a syntax such as
$foo as ?int
since all
existing types of coercion are already possible via the cast syntax
(please correct me if I'm wrong).
The current cast syntax (and its functional version, intval()
etc) only performs a single "type of coercion": make a best effort to guess the value, silently use a fallback value, never fail. (int)'123hello' is 123, (int)'complete nonsense' is 0. It also doesn't support nullable types, union types, etc, and it's not clear what it should do if it did.
There is currently no syntax or function to explicitly perform the coercion that mode 0 scalar parameters perform, where '123hello' and 'complete nonsense' both produce a TypeError. Nor is there any syntax or function that can answer the question "would this value be accepted as {type} in mode 0?"
In almost every case you would need coercion you also need validation,
and validation is not something that's possible with a neat syntax,
I don't see why validation can't be concise, for extremely common cases, such as "Is this string obviously an integer?"
at least not this one
I'm not sure what you mean by that; I consider the syntax to use very much an open question, and if I get time to write up a proposal, would like to discuss the pros and cons of various options.
That could be as simple as a built-in function, but might benefit from first-class syntax so that it can be used with any type without passing it as a string.
Regards,
Rowan Tommins
[IMSoP]
From: Gina P. Banyard internals@gpb.moe
Sent: Wednesday, June 19, 2024 5:08 PM
On Tuesday, 18 June 2024 at 17:37, Robert Landers
landers.robert@gmail.com wrote:Hello internals,
[...]
What are your thoughts?
As self-proclaimed leading expert on PHP type juggling.
That it is a terrible idea with no gains whatsoever.
Renaming the declare statement does not improve the situation.PS. Personally, I would rather unify non-strict and strict in some way
that makes sense ... so, that route sounds nice too.See my old meta RFC: https://github.com/Girgias/unify-typing-modes-rfc
It is a somewhat known hot take from mine that I think the strict_type
declare statement was a mistake. [1]
Mainly because it affects barely nothing in regard to the engine.I have written/co-authored multiple RFCs over the years to make the
default coercion mode less whack. [2][3][4][5][6][7]
And my container/offset RFC is in the same vein [8] which lead me into a
different rabbit hole then the one I was expecting to explore which is
addressing PHP's weird comparison semantics. [9]Therefore, I would rather we focus on actually fixing PHP's semantics,
than arguing about changing the name of something that shouldn't really
exist in the first place.
Talking about 'going back in time' and sanitizing type coercion, I immediately had to think about the rejected 'Coercive Types for Function Arguments' RFC Zeev created as an alternative to the 'Scalar Type Declaration' RFC which was ultimately chosen and implemented.
https://wiki.php.net/rfc/coercive_sth
It seems that parts of what that RFC suggested have been implemented over time. In retrospect maybe this should have been the direction?
--
Vincent de Lau
[1] Slide 68 of my PHP UK talk "PHP's Type System Dissected":
https://gpb.moe/doc/slides/PHP_Type_System_Talk_PHPUK2023.pdf
[2] https://wiki.php.net/rfc/saner-numeric-strings
[3] https://wiki.php.net/rfc/implicit-float-int-deprecate
[4] https://wiki.php.net/rfc/saner-inc-dec-operators
[5] https://wiki.php.net/rfc/locale_independent_float_to_string
[6] https://wiki.php.net/rfc/exit-as-function
[7] https://wiki.php.net/rfc/deprecate-boolean-string-coercion
[8] https://github.com/Girgias/php-rfcs/blob/master/container-offset-
behaviour.md
[9] https://github.com/Girgias/php-rfcs/blob/master/comparison-equality-
semantics.md
Le 20 juin 2024 à 13:08, Vincent de Lau vincent@delau.nl a écrit :
From: Gina P. Banyard internals@gpb.moe
Sent: Wednesday, June 19, 2024 5:08 PMOn Tuesday, 18 June 2024 at 17:37, Robert Landers
landers.robert@gmail.com wrote:Hello internals,
[...]
What are your thoughts?
As self-proclaimed leading expert on PHP type juggling.
That it is a terrible idea with no gains whatsoever.
Renaming the declare statement does not improve the situation.PS. Personally, I would rather unify non-strict and strict in some way
that makes sense ... so, that route sounds nice too.See my old meta RFC: https://github.com/Girgias/unify-typing-modes-rfc
It is a somewhat known hot take from mine that I think the strict_type
declare statement was a mistake. [1]
Mainly because it affects barely nothing in regard to the engine.I have written/co-authored multiple RFCs over the years to make the
default coercion mode less whack. [2][3][4][5][6][7]
And my container/offset RFC is in the same vein [8] which lead me into a
different rabbit hole then the one I was expecting to explore which is
addressing PHP's weird comparison semantics. [9]Therefore, I would rather we focus on actually fixing PHP's semantics,
than arguing about changing the name of something that shouldn't really
exist in the first place.Talking about 'going back in time' and sanitizing type coercion, I immediately had to think about the rejected 'Coercive Types for Function Arguments' RFC Zeev created as an alternative to the 'Scalar Type Declaration' RFC which was ultimately chosen and implemented.
https://wiki.php.net/rfc/coercive_sth
It seems that parts of what that RFC suggested have been implemented over time. In retrospect maybe this should have been the direction?
Hi,
The RFC you are pointing to was about introducing a new, more restrictive (and saner) set of automatic coercion rules in the context of function arguments only. For instance, substr('xy', 1.2)
would have been deprecated, but 3 % 1.2
and ['x', 'y'][1.2]
would have continued to “work” (for some stretchy definition of “work”).
What has been implemented over time, is making the existing set of automatic coercion rules more restrictive (and saner) in all contexts. For instance, all of substr('xy', 1.2)
, 3 % 1.2
and ['x', 'y'][1.2]
are deprecated.
—Claude