Generify collections using Psalm#177
Conversation
|
Huge 👍 from me on this. This is meta-code that provides immediate value for downstream consumers that use Psalm, without any runtime being affected. The only possible issues that might arise are with |
|
To be checked: scrutinizer-ci failure (can't run |
|
Needed to bump the PHP version to allow the installation of Psalm to complete. Should be no issue though, since it went from 7.1.0 only up to 7.1.3 |
|
@Ocramius sure, will do. |
weirdan
left a comment
There was a problem hiding this comment.
Overall, it might make sense to use two generic parameters for Collection: Collection<TKey,TVal>, so that people may narrow down the key type further:
/** @psalm-var Collection<string,string> $coll */
$coll = new ArrayCollection;
$coll->containsKey(42); // then Psalm will be able to flag this as invalid| * | ||
| * @return bool TRUE if the predicate is TRUE for at least one element, FALSE otherwise. | ||
| * | ||
| * @psalm-param Closure(int|string, T):bool $p |
There was a problem hiding this comment.
@psalm-param Closure(int|string=, T=):bool $p should have the same effect I think?
| * contains the collection of elements where the predicate returned FALSE. | ||
| * | ||
| * @psalm-param Closure(int|string, T):bool $p | ||
| * @psalm-return Collection<T>[] |
There was a problem hiding this comment.
You can also use @psalm-return array{0: Collection<T>, 1: Collection<T>} for explicitness
Accepted as a sign I agree with this. Some work still left to do though
|
Thank you for the review guys, especially @weirdan for all the suggestions. Going through them atm, but I think we should agree on whether to use |
Found while reviewing doctrine/collections#177 Also: - Limited key type to array-key - Added future tests, pending psalm implementation (see vimeo/psalm#1462)
The key can be |
|
@muglug if all those |
|
@nschoellhorn You will need to adjust ArrayCollection signatures as well (things like |
alcaeus
left a comment
There was a problem hiding this comment.
👍 I'm in favour of this. We should try to allow our users to make full use of the static analysis tools they provide. Since psalm provides functionality around generics, this makes perfect sense. Once phpstan supports something like this, we should add that as well. Of course, I'd prefer it if @muglug and @ondrejmirtes could come up with an annotation that doesn't include a tool prefix, but that's for them to settle, not us.
Last but not least, checking our code with phpstan and psalm is also a plus as there are some things that are not detected in both tools, so this should improve the code quality as well.
Yeah, I'm usually more aggressive about annotation adoption, I'm not worried about using new syntax in at-param, at-var etc. Thanks to shoving intersection types there, they are currently supported by PhpStorm and other tools, which was my goal (driving innovation). |
Sadly, Psalm does not seem to catch that. I tried that with my test repository that I linked above and when running Psalm after removing the annotations from
Yeah, still at it. Going for an additional template parameter |
While I'm all in for adding psalm specific notations here (since there doesn't exist any standard for this so far), I'm not in favor of incorporating psalm bug specific workarounds. This is something that should be fixed by upstream (psalm), not us having to copy these to every subclass. |
Must back this too: |
|
I'd also prefer that. Maybe @muglug can check if there's something that I've done wrong, causing the inheritance not to work properly. If it's not my fault, I'd offer submitting an issue to Psalm. |
|
Well, that seems to be fixed: https://github.com/vimeo/psalm/releases/tag/3.2 |
|
Yup, thanks for letting me know! Templated inheritance is non-trivial. I already had it working for templated return types, but had neglected templated param types. |
weirdan
left a comment
There was a problem hiding this comment.
I think it'll be good to merge after this round of suggestions.
|
After another round of improvements (thanks @weirdan), we are now only missing the discussion on the (possibly) optional parameters of the closures for |
weirdan
left a comment
There was a problem hiding this comment.
Collection::partition() should probably be able to accept argless closures. Other than that this looks fine.
Signed-off-by: Niklas Schoellhorn <schoellhorn.niklas@gmail.com>
|
Thank you @muglug for the fast update once again. I've bumped the dependency of Psalm to the new version and rolled back the change regarding |
Ocramius
left a comment
There was a problem hiding this comment.
@doctrine/doctrinecore can I have a vote on this, please?
SenseException
left a comment
There was a problem hiding this comment.
Looks neato.
If some psalm annotations change in the classes/interfaces, would this break psalm checks of other projects using Collections?
|
Yes, type checks propagate statically |
|
Should we have some kind of tests that prevent logical changes in the psalm annotations of doctrine/collections? |
|
That would be like |
You can take a look at https://github.com/weirdan/doctrine-psalm-plugin/blob/master/tests/acceptance/Collections.feature - most of those tests would apply here as well. Feel free to borrow them. |
|
Looks good, I can add that if wanted. |
|
Let's please defer that for now |
|
Or better: separate patch (based on this one) |
|
Sure, I will prepare one soon then. |
|
Right, calling the merge here 🚢 |
I've talked to @Ocramius and we find that generics/template types would make a very good addition to this library. Since PHP doesn't come with that feature natively, I have decided to implement it using Psalm and Psalm's template annotations.
How is that useful?
A lot of people already use static analysis to reduce the risk of introducing bugs in your application. Psalm is one of the most popular tools out there to do that. By adding the annotations to Psalm and using the correct
@psalm-varannotations when using the collections in projects, Psalm makes sure that you only put values of the right type in your collection automatically, since it also scans thevendordirectory.I have created a very minimal proof of concept project over at nschoellhorn/psalm-collections-test. You can clone that, install the dependencies and run
./vendor/bin/psalmto check it out.