Renaming "strict types" to "scalar type coercion"

php.internals

Robert Landers

2 years ago
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

Claude Pache

2 years ago
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

Robert Landers

2 years ago
On Tue, Jun 18, 2024 at 9:18 PM Claude Pache <claude.pache@gmail.com> wrote:
> > 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 use `strict_types=0` when invoking the callback. Changing that would also be a big BC break. > > —Claude
Robert Landers Software Engineer Utrecht NL

Rowan Tommins [IMSoP]

2 years ago
On 18/06/2024 17:37, Robert Landers 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); 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]

Robert Landers

2 years ago
On Tue, Jun 18, 2024 at 10:46 PM Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk> wrote:
> > On 18/06/2024 17:37, Robert Landers 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 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.
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

Rowan Tommins [IMSoP]

2 years ago
On 19/06/2024 09:30, Robert Landers wrote:
> 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]

David Gebler

2 years ago
On Tue, 18 Jun 2024, 17:40 Robert Landers, <landers.robert@gmail.com> wrote:
> 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

Robert Landers

2 years ago
On Tue, Jun 18, 2024 at 11:04 PM David Gebler <davidgebler@gmail.com> wrote:
> > On Tue, 18 Jun 2024, 17:40 Robert Landers, <landers.robert@gmail.com> wrote: >> >> 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

David Gebler

2 years ago
On Wed, 19 Jun 2024, 09:31 Robert Landers, <landers.robert@gmail.com> wrote:
> > 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

Michał Brzuchalski

2 years ago
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 ```ini # 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

Mike Schinkel

2 years ago
> On Jun 18, 2024, at 5:04 PM, David Gebler <davidgebler@gmail.com> wrote: > > On Tue, 18 Jun 2024, 17:40 Robert Landers, <landers.robert@gmail.com <mailto:landers.robert@gmail.com>> wrote: > 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

Gina P. Banyard

2 years ago
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

Larry Garfield

2 years ago
On Wed, Jun 19, 2024, at 10:07 AM, Gina P. Banyard wrote:
> 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

Sebastian Bergmann

2 years ago
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.

Robert Landers

2 years ago
On Wed, Jun 19, 2024 at 5:43 PM Sebastian Bergmann <sebastian@php.net> wrote:
> > 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

Rowan Tommins [IMSoP]

2 years ago
On 19/06/2024 16:34, Larry Garfield 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. Regards,
-- Rowan Tommins [IMSoP]

Paul Dragoonis

2 years ago
On Thu, Jun 20, 2024 at 11:54 PM Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk> wrote:
> On 19/06/2024 16:34, Larry Garfield 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 1. typing "declare(strict_types=1);" is already cumbersome enough, we don't need to be adding more words and complexity to it 2. 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" 3. 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 4. 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

Paul Dragoonis

2 years ago
On Fri, Jun 21, 2024 at 10:12 AM Paul Dragoonis <dragoonis@gmail.com> wrote:
> > > On Thu, Jun 20, 2024 at 11:54 PM Rowan Tommins [IMSoP] < > imsop.php@rwec.co.uk> wrote: > >> On 19/06/2024 16:34, Larry Garfield 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.

Robert Landers

2 years ago
On Fri, Jun 21, 2024 at 12:54 AM Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk> wrote:
> > On 19/06/2024 16:34, Larry Garfield 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

Pierre

2 years ago
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

Rowan Tommins [IMSoP]

2 years ago
> 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. On Fri, 21 Jun 2024, at 13:46, Pierre wrote:
> > 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

2 years ago
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.
> > On Fri, 21 Jun 2024, at 13:46, Pierre wrote: > > > 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

Robert Landers

2 years ago
On Fri, Jun 21, 2024 at 3:01 PM Pierre <pierre-php@processus.org> 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); > > 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

Pierre

2 years ago
Le 21/06/2024 à 15:57, Robert Landers a écrit :
> On Fri, Jun 21, 2024 at 3:01 PM Pierre <pierre-php@processus.org> 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); >> >> 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

Robert Landers

2 years ago
On Fri, Jun 21, 2024 at 5:49 PM Pierre <pierre-php@processus.org> wrote:
> > Le 21/06/2024 à 15:57, Robert Landers a écrit : > > On Fri, Jun 21, 2024 at 3:01 PM Pierre <pierre-php@processus.org> 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); > >> > >> 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.

Rowan Tommins [IMSoP]

2 years ago
On Fri, 21 Jun 2024, at 15:21, Pierre wrote:
> 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]

Vincent de Lau

2 years ago
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

Claude Pache

2 years ago
> 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 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?
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