Problem/Motivation
Drupal 9 began to add return types including object return types.
I can not find a "fixed" issue where this decision was made nor can I find a change record announcing this.
The only place this new policy is mentioned is in https://www.drupal.org/docs/develop/standards/coding-standards#s-paramet... -- but for example https://www.drupal.org/docs/develop/standards/object-oriented-code#hinting doesn't mention return types.
While PHP 7.2 added (limited) contravariance support by removing type restrictions on parameters, return types are restricted to the original before PHP 7.4.
This makes the life of core/contrib developers rather hard.
Steps to reproduce
Proposed resolution
Remove object return typehints from D9 and add a change notice outlining that a) scalar return typehints should be used in D9 b) all return typehints should be used in D10. My meagre grep skills found 84 outside of test code. Here's my attempt at grepping for them:
ag -G php ' function.*\) ?:' core|grep -vi test|grep -vP '(array|string|void|int|bool|float)\s*[{;]?$'|
The problem is
core/modules/jsonapi/src/Normalizer/Value/TemporaryArrayObjectThrowingExceptions.php:113: public function getIterator(): \Iterator
In D9 it should be
core/modules/jsonapi/src/Normalizer/Value/TemporaryArrayObjectThrowingExceptions.php:113: public function getIterator()
Remaining tasks
Decide, code, commit.
User interface changes
N/A
API changes
None. https://3v4l.org/YDrXB existing code is unaffected.
Data model changes
N/A
Release notes snippet
N/A
Comments
Comment #2
ghost of drupal pastComment #3
ghost of drupal pastComment #4
andypostComment #5
cilefen commentedComment #6
andypostI think it's not a bug, moreover projects using PHP 7.3 should be in a middle of migration to 8.0 as PHP has 3 year support of releases (no matter what distributives tells about support).
Even RH/centos already announced changes in its release cycle. So projects/customers who can't fit into 3 year cycle of Drupal has to reconsider their expectations.
I think it should be closed (wont-fix) as it's nothing about developers but I agree that object type hints should be used carefully (most of places it should be interfaces)
Comment #7
ghost of drupal pastIf core remains on 7.3 then , I suppose , contrib should at least attempt to support 7.3 as well and that's where this will be a lot of unfun. Also, core development: I already ran into problems with this when I tried to write a patch with select extenders. Edited the IS to emphasize this. Obviously (?) custom code is on PHP 8 already so that's not a concern.
Comment #8
ghost of drupal pastHrmmm https://3v4l.org/20TMV https://3v4l.org/eNTiD#v7.3.33 interesting, you are right, I was unaware of this. Then there's only 43 to be removed from D9, even easier.
Comment #9
catch@chx why can't you increase the minimum version of PHP in your own modules in .info.yml?
Comment #10
xjmSo I disagree that a few missing features in PHP 7.3 is anything other than a minor annoyance for developers. The benefit of using strict typing where possible (in terms of preventing critical and major bugs due to bad inputs without internal error handling for them, and explicitly defining the contract of an API with clean fatals) vastly outweighs the minor initial confusion that could result from someone not remembering that you can't have union types or typehint your class member properties yet.
Furthermore, if someone does forget, well, that's why we have test coverage. Tests exist because no developer knows everything, nor even knows the things they know all the time. PHP linting is done on all supported PHP versions at commit, so any syntax that isn't compatible with all supported PHP versions gets fixed promptly without any real hassle.
Furthermore, it's been our goal since PHP 7 was released to eventually get to the point that we use typehints everywhere, because they prevent so many bugs. We've only just been able to start adding them because of 8.7 going EOL 1.5 years ago, and were able to start adding them in a few more places when nullable types became possible when coverage for 8.9 wound down. We'll add them in even more places in D10 when we can use union types (and therefore enable phpcs rules to enforce typehinting).
In all cases though this is just adding them to new code, because adding them to old code is a BC break that has to be introduced by deprecation in a minor + removal in the next major. I see no reason to set ourselves back by 6-12 months of effort just because of a once-a-month brief revert or minor hotfix with an obvious and simple solution.
Finally, the 9.x branches are in bugfix mode, not "big disruptive standards changes" mode. Ripping typehints out of 9.4.x would (a) be a regression (b) require adding test coverage and additional, manual type error handling everywhere they are used, and (c) complicate backports for bugfixes and security coverage to 9.3.x and 9.2.x. 9.2.x only gets commits for security updates.
So, for me, this would be wontfix for the above reasons.
Thanks!
Comment #11
xjmOh re: class vs. interface typehints, this has already been covered by policy for 10 years. You typehint the broadest possible interface when the interface is the public API; you typehint the class in the less common case that a class is the public API. But those things aren't new! Class typehints have existed since PHP 5.2 or 5.3 I think. So that's already covered by policy that's been in place since 2012. It's only scalar and nullable typehints that are new in PHP 7 versions (and union types etc. in PHP 8).
Comment #12
xjmIt is a fair point that there should have been a change record advising contributors of the refined coding standard. Not sure how we missed that. I think what happened is that we kept #3154762: [policy, no patch] All new Drupal 10 code should use appropriate type hints wherever possible open because there are follow-ups to solve like adding typehints to existing code in a BC way, and our mental checklist for change records happens typically when an issue is marked fixed. We can add that now.
Comment #13
ghost of drupal pastSorry the issue title missed the word "return" -- sorry.
I am failing communicate the problem across apparently.
The problem is
core/modules/jsonapi/src/Normalizer/Value/TemporaryArrayObjectThrowingExceptions.php:113: public function getIterator(): \IteratorIn D9 it should be
core/modules/jsonapi/src/Normalizer/Value/TemporaryArrayObjectThrowingExceptions.php:113: public function getIterator()This is all.
Comment #14
effulgentsia commentedThe concern is that some contrib modules might need/want to subclass a core class, override one or more of its methods, and in that overridden method narrow the return type, right? What are some examples of where contrib needs to do that? What would be the inconvenience to contrib of keeping the return type of overridden core methods the same as core's, until after Drupal 9 is EOL?
Is there an issue where that patch is posted?
Comment #15
xjmAh, I get the concern now:
https://3v4l.org/eEuTg
This requires that contrib is extending both the calling class and the typehinted return interface. Possible examples might be in the entity API, e.g. where core would have
EntityInterfaceobjects and methods that returnEntityInterfacein whatever caller API, but a contrib entity API might want to specifyMyEntityInterfacein its implementation of that caller API.The solution to this is just that core and contrib should continue to use the broadest possible typehints (e.g.
EntityInterface) as documented in the coding standards, for as long as they continue to support Drupal 9. I.e., this:https://3v4l.org/DPpCJ
The contrib can narrow the contract to
MyEntityInterfacein D10, but at least it's a clean fatal until then.It is potentially a core bug if anywhere we have the opposite problem, where core's typehint is too narrow. (This is an issue for parameter typehints as well.) But if we have a case like that, I'd suggest a specific bug report for it as hinted (pun not intended...) in #14.
Comment #16
ghost of drupal past#3260507: Improve the discoverability of select extenders was the first issue where I ran into this.
This works as intended -- the specific factory returns a specific class. But you can't have a parent for them -- even if your base return typehint is an interface: https://3v4l.org/7kurh#v7.3.33 work with 7.4+ https://3v4l.org/7kurh
Comment #17
ghost of drupal pastComment #18
cilefen commentedBased on #15 it is wrong and is a bug to have overly-narrow type hints. If that is the conclusion can we close this as answered?
Comment #19
ghost of drupal pastNevermind.
Comment #20
ghost of drupal past