Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify psalm types #112

Merged
merged 8 commits into from
Feb 13, 2020
Merged

Clarify psalm types #112

merged 8 commits into from
Feb 13, 2020

Conversation

andyg0808
Copy link
Contributor

I noticed that some of the Psalm types added in #111 could be made more precise, so I cleaned them up a bit.

I'm very interested in feedback on my decision to mark all the static methods as external-mutation-free rather than mutation-free. It's more correct to use external-mutation-free as I've done, but then it's invalid to call the Enum functions in immutable contexts:

EnumSubclass::ENUM_VALUE()

is disallowed in a function marked psalm-immutable, because of the internal mutation of the cache array. The mutation seems insignificant, since it could be omitted with no change to the results (other than in speed), so I'd like to find a way around this.

I can see two approaches which would allow the use of Enums in immutable contexts (three, if you count the user ignoring the Psalm errors):

  1. Lie to Psalm and tell it that toArray is immmutable. This seems tolerable (despite how bad a practice overriding the typechecker is) because the mutation is entirely memoization. If PHP were a lazy language, no caching would be necessary in the first place.
  2. Do the reflection up-front. Run toArray in the constructor and look up the value there. __callStatic can in fact be marked pure if this approach is taken. I've written the code for this in the iFixit/php-enum@clarify-psalm-types...iFixit:make-callstatic-pure branch; feel free to ask for a PR from that if you like that approach.

Andrew Gilbert added 5 commits February 10, 2020 12:53
They all modify the cache, so they can't be `mutation-free`, and they
rely on the object state, so they're not `pure`.
This makes it so Psalm doesn't think we're passing `mixed` values
around. We're either constructing using an instance of ourselves, or
using a value which we're going to wrap.
Might as well be more precise about this, as Psalm supports doing so.
This makes it clear that we're not passing `mixed` values around.
@mnapoli
Copy link
Member

mnapoli commented Feb 11, 2020

Thank you for all these details!

I had a look at the code diff for solution 2, I don't think it is worth changing the code so much (and the external API of the class, i.e. the constructor parameters) just for Psalm annotations.

I am fine suppressing the error here (solution 1), and you describe very well the reasons why.

Having enums as immutable is a must-have IMO.

@andyg0808
Copy link
Contributor Author

andyg0808 commented Feb 12, 2020

Discussed last two commits with @jarstelfox; better solution incoming.
Looking at it more, we couldn't use it from a pure context without marking it as pure, so this seems reasonable.

@@ -86,6 +86,7 @@ public function getKey()

/**
* @psalm-pure
* @psalm-suppress InvalidCast

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change doesn't seem to match the title of the commit.

Copy link
Contributor

@jarstelfox jarstelfox Feb 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, somehow I messed these commit messages up! Fix incoming

Fixed

This means every function can be called from an immutable / pure context

Note: ToArray will fail psalm on this commit as (rightfully) there is an impure psalm issue

This commit is a bit of a lie to psalm: Psalm is correct that our object is not actually immutable / pure.

But is if you remove caching.

This lie seems tolerable (despite how bad a practice overriding the typechecker is) because the mutation is entirely memoization.
See previous commit.

Psalm isn't actually wrong here, but we are willing to lie to psalm
since the impurity is just an internal cache.
This happened due to a bad find replace
@jarstelfox
Copy link
Contributor

We should be good to go now 😊

@mnapoli
Copy link
Member

mnapoli commented Feb 13, 2020

Thank you both!

I'll be merging and releasing. FYI there is #113 that might interest you as well.

@mnapoli mnapoli merged commit aef7b9f into myclabs:master Feb 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants