It’s not about whether a few experts on this forum can understand the error message, it’s about what will be best understood by most users.
The current error message:
fails to identify which line the error occurs on,
fails to identify which function is causing the error,
poorly communicates what’s actually causing the error, and
does not offer the user any constructive solutions.
I encourage you to read the current error message aloud to a spouse or roommate, or get Google to read it aloud to you. Then compare against my suggested rewrite. Here’s the comparison:
ERROR: TypeError: in keyword argument length, expected Union{Nothing, Integer}, got a value of type Float64.
. . .
ERROR in range(): Keyword argument length was entered as type Float64, but should be of type Integer.
I am of course very biased, but it’s hard to believe that any neutral party would say the current error message is better in any way, compared to my suggested rewrite. Are there some merits to the current error message that I’m not understanding?
I would prefer: TypeError in range(): Keyword argument length was entered as type Float64, but should be a subtype of Union{Nothing,Integer}.
starting with TypeError i already know that one function has an incorrect input. The ERROR: TypeError is superfluous. on the type suggestion, Union{Nothing,Integer} is not a concrete type, so the error message should explicitly say that the input is not a subtype, instead of is not an expected type.
This is a problem of the environment in which you’re coding. When you’re executing scripts, Julia does point out the line that caused the error. This might be solved by the plugin for VS Code, but I don’t know if it is possible or feasible (hope it is).
Think this could be changed, as pointed out by @trahflowhere. I think is worth filling an issue.
I disagree with this, as it does say that you’re passing the wrong type to the argument. That the expected type Union{Nothing, Integer} is not trivial to understand coming from another languages is not a problem of Julia. I would argue that this is something almost every user will need to learn.
This is hard to address because of how the language was designed, as the error is not properly caused inside the function, and we don’t have traits as a first class language feature. I don’t see how this could be done.
I do like more the way you phrase the error, it looks clearer than the current one.
Given my roommates are either computer scientist or from humanistic areas, I would get wildly different responses.
Jokes aside, your criticism is very constructive, just that I don’t think your last point is easily solvable. At least not yet.
The first line shows the error to be on line 5, which is indeed correct. You have to toggle line numbers in cells though, default is (as in regular Jupyter notebooks) that they’re switched off:
A length of type Nothing is allowed, so the current error message is correct, while the suggested rewrite is not. One may discuss whether the range function should allow length=nothing, but given its current implementation the error message is fine.
To be fair, while it doesn’t lie, it is hard to interpret for a beginner.
ERROR: TypeError: in keyword argument length, expected Union{Nothing, Integer}, got a value of type Float64
This makes it sound like the argument should be of type Union{Nothing, Integer}. Except, how does one create that type?
julia> Union{Nothing, Integer}(3)
ERROR: MethodError: no method matching Union{Nothing, Integer}(::Int64)
That doesn’t work, and it also doesn’t tell me what I should do. One can search for help on Union, but that’s probably a waste of their time for something so trivial.
Unless I know that Union{Nothing, Integer} means “either an Integer, or nothing”, it’s not obvious to a beginner. I would say that the error message might be improved here to make it easier to understand. A beginner shouldn’t be required to understand Union types to get their work done, that’s an unnecessarily steep learning curve when there’s a simpler solution.
Also, if someone specifies a numerical value for length, it’s probably reasonable to assume that they don’t intend that argument to be nothing. The fact that it may accept nothing is likely irrelevant in this context.
Are you suggesting hardcoding it for the range function, or changing how Union is printed generally? Because to me reading about how Union types work isn’t that high a requirement. It’s easily googleable (Julia Union gets you right there), and once you know what it means it’s a more compact description than natural language versions, especially for larger union types.
I’m suggesting changing how a TypeError is shown if the expected type is a Union. Instead of Union{Nothing, Integer} it may say “an Integer or nothing”, which conveys the same information.
I understand that Union{Nothing, Integer} is a more compact description that’s googleable, however, in this case, the bar to a user-friendly error message doesn’t appear to be high.
I think that @gustaphe’s concern is about scalability when the Union gets more complex (e.g. nested).
Integration with a clickable Union link to a doc pane (à la RStudio) in vscode could be a good trade-off between current compact error message (which drives you toward a better understanding of Julia’s type sytem) and user-friendlyness.
I’d say, as a beginner, it is worth spending time learning the error message. Or in other words, beginners should learn how to read the basic error message. Here, Union is a thing to learn, whether you like it or not, you will encounter it sometime.
How about changing the help text so it says type of X when X is a concrete type and subtype of Y when Y is an abstract type? I would say that trying to find an object that is an instance of a Union{Integer, Nothing} is indeed confusing because it can’t be done in that sense.
I agree so much with this. It was one of the first thing I tried to learn and it was immensely helpful (and it is always one of the first things I teach in classes).
I think the error message really just lacks the information that the keyword argument length directly refers to the range() function.
I honestly think something like (as suggested by @nilshg)
expected value to be of type Integer or Nothing, got a value of type Float64
is just more confusing, because this could also mean that 2 functions exist, one of which expects an Integer, one of which expects type Nothing (obviously nonsense with Integer, but not in other Union cases).
My hope would be that explicitly referring to the function is helpful to beginners e.g.
ERROR: TypeError: in keyword argument length of function range(), expected Union{Nothing, Integer}, got a value of type Float64