fsharp
fsharp copied to clipboard
Can we improve somewhat on FS0001 errors of the form "The type X does not match the type Y"
I would like to discuss improving the errors where an expected type is not equal to a given type. My problem with such errors is, they are virtually impossible to read or understand, even after years of programming experience, unless for the most trivial of cases.
For instance, just now I hit this:
Does this mean that Result.create
cannot understand a -> string
as first argument, or does it mean that the type in the list is not supposed to be of type a -> string
but should be of type string
? Or does it mean that the part before |>
results somehow in a XResult<string>
and this is not a proper type for Result.create
which expects Result<('a -> string), 'b>
?
It's not that it is impossible to find out, but I think the main problem is what we call in linguistics: interchangeable object/subject in a sentence, so that you cannot be certain what the message is talking about. It says apples are not equal to pears, but we know that, it doesn't add anything.
Suggestions
I could think of several ways of improving the error. I am not sure what kind of context information is available in the F# compiler, but here are some ideas:
- The type 'XResult<'a -> string), 'b>' cannot be used as the lh-side of this '::' operator, the rh-side is already bound to 'XResult<string>'.
- The first generic parameter for 'Result.create' is expected to be of type 'XResult&tl;string>', but given a value of type 'Result<'a -> string), 'b>'.
- The function 'Result.create' expects a parameter of type X, but the given parameter is of type Y.
I'm sure some variant can be concocted that is at least somewhat clearer than "the type X does not match the type Y", because that is just as telling as saying "42 does not equal 24": it doesn't explain anything, basically.
I get your point and you're right. I don't know whether we can do much here but I'm going to take a bit time to look into it :)
@realvictorprm, that's much appreciated! Even if we have little room for improvement, for instance because there is not enough contextual information, perhaps we can at least make sure it is clear what the error is talking about (a value, a function, an argument to a function, an argument returned from a function, the return value of a function that doesn't match the expected value of a parameter etc).
(and, fwiw, a day later, looking at the same screenshot, I am again lost to what it means. I can figure it out again, but it is just too puzzling imo).
I'd like to bump this, as it's still an issue, especially with types that are from different namespaces, but share the same name. eg,
Type mismatch. Expecting a 'Problem -> 'a' but given a 'Problem -> HttpStatusCode * Problem' The type 'A.Problem' does not match the type 'B.Problem'
It's incredibly difficult to reason about the function types without namespaces in this error.
I’m working with a team now that’s largely new to F# and this proved to be one of the main pain points during transition from other technologies. I know a lot of errors have improved over the years, but not this one.
Msybe I should take a crack at this. @dsyme would you know where this is actually done? I should be able to find it, but if you have pointers… and would you (in principle) accept a PR? Any gotchas I should be careful about?