-
-
Notifications
You must be signed in to change notification settings - Fork 367
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
Reduce use of partial functions from HLS #2514
Comments
Could you share a few examples? |
30-odd usages of I think many of these are fine, but therefore usually trivial to avoid. It would be nice to have a blanket "no partial functions" rule. |
30-ish |
I volunteer to work on this, as I wanted to contribute to hls in more substantial way. haskell-language-server/ghcide/src/Development/IDE/Core/Shake.hs Lines 854 to 867 in 070f16f
Can we prove these will never fail? What should the functions do in case of empty lisis? Should they maybe accept non-empty lists as inputs (as in https://www.parsonsmatt.org/2017/10/11/type_safety_back_and_forth.html)? My preliminary plan is this:
|
The plan sounds really great to me, given at minimum we will have more info about the error. |
The plan sounds good to me too. A 4th bonus step would be to promote the Re: That's just from looking at the definitions of the functions! So I think you can probably get quite far without too much domain knowledge. |
|
Let's make sure to validate these changes before applying them: |
Correct, it can't fail. However,
So I agree it's safe, but if it's trivial to rewrite it so we don't even need to think about whether it's safe, that seems like a win to me. |
I was actually asking for examples of user reported crashes due to these partial functions. There haven't been that many as far as I can remember, and most if not all of them in the code action providers. Having a catalogue of those would help keep this effort productive. |
I don't have a catalogue. Someone reported one on IRC yesterday, which is what sent me down this path. They got no stack trace, which of course makes it hard to know which example to blame... Personally, I think it's cheap enough to just get rid of all uses, and then we just never have to worry about this again. Sometimes I feel like "it's okay for me to use |
Using |
Do we want to call |
Ah yes, this was what came out of the report on IRC: #2518 |
If we do this, let's make sure to ban all partial functions using Reviewing the plan with this in mind:
|
It was me who reported on irc and made mentioned. Just wanted to add that from the user point of view it is important to avoid crashes, because vscode is pretty bad at informing that there was a crash (and where). Since vscode+hls works in most cases perfectly out-of-the-box is a great feature for beginner haskellers. But then, when such crash happen, it is extremely hard for such person to identify what happened. |
On #2537 So different levels of |
Great idea! Long ago I ran into an issue that could have been from a partial function or with this change would have given a better error in #1618 |
Another victim: #2639 (comment) |
In all fairness, that call to head is probably in the test body itself |
Yes: let's not use partial functions in tests either! |
|
Edit: This error happened running I'm trying to update our work codebase to hls 1.6.1.0 and I got an error that's not helpful:
Going to the source you can see it's because I don't have an
But because of the partial function, if I hadn't known how to track this down, I never would have known about the template Haskell warning. |
Nota bene: As I was around this theme & two times promised to attend to a particular reduction of the
|
IMO, partial functions are fine, if there is sufficient local proof that it is total in the given context (e.g. the input to a partial function is controlled by the outer function itself). #2672 (comment) is an example where no such local proof is possible and the callstack is actually really long. So the caller cannot make any reasonable assumption about On the other hand, I don't think a function like this needs any adjustment: foo :: ShortByteString -> ShortByteString
foo sbs
| null sbs = sbs
| last sbs == _space = "lol"
| otherwise = "shrug" So I'm not too thrilled about enforcing hlint compliance. It's a nuisance. |
I agree it is a nuisance but I would like to give here a different perspective: if hls crash for a beginner user, they are basically clueless what happened. Even if able to find So it's a nuisance for developer, but if the things go wrong way, for a user it is a deal breaker. |
I think we need a hlint ratchet, even if it's going to be very tedious to whitelist all the existing usages. At the moment it's way too easy for people to introduce new partial function usage, even when it's very easy to avoid. We need something to slow that down. |
Ratchet started here: #2974 |
Ratchet committed, you can now use |
Why wouldn't you want to replace that with this? foo :: ShortByteString -> ShortByteString
foo sbs = case unsnoc sbs of
Nothing -> sbs
Just (_, x)
| x == _space -> "lol"
| otherwise -> "shrug" |
Because that easily gets ridiculous if you want to look at the first 8 characters. I have a lot of those examples from the filepath package, but I'm not gonna list all of them here. |
HLS has quite a lot of use of partial functions. I'm sure many of these are benign, but we do occasionally get users reporting crashes with such (usually totally useless) errors.
Gradually reducing these is an easy, helpful thing for someone to do. Good new contributor issue!
The text was updated successfully, but these errors were encountered: