I often find error messages like this impractical:
julia> only([1, 2])
ERROR: ArgumentError: Collection has multiple elements, must contain exactly 1 element
We don’t know what the Collection is, we don’t know what the elements are, we don’t know how many there are (only multiple). If I find this in the logs of a crashed CI run or so, where I can’t easily go in and check out runtime values, it’s unhelpful. Because of this I often find myself writing my own only check just so I can have a more informative error, which kind of defeats the purpose of the function.
For the above example, the message could theoretically be:
julia> only([1, 2])
ERROR: ArgumentError: [1, 2] has 2 elements, must contain exactly 1 element
However, I recognize that it’s hard to rewrite the error message generically.
You could write the type instead of Collection but that might be a huge thing. We could print all the elements if there are at max let’s say five or so, but not after that as there could be way too many. For general iterators, we usually don’t know how many elements there are because only errors already at the second one. Etc. etc., so we end up with what I posted above.
I would like to get a discussion and sharing of strategies going, and maybe collect some ideas for changes in Julia of similarly uninformative error messages. What do other languages who are praised for their good error messages doing? Can we copy some approaches?
The only example makes me think the idea should be to give the proof of the error condition.
For only, we need to prove it has 2 elements, no more.
It would be nice to have a Base function abbreviated_type to use in error messages.
In another post I tried Elm style errors, and Mason came up with a macro to use like
function f(x::Real)
if x>= 0.0
x + 1
else
@noinline_block x throw(DomainError("f requires inputs greater than 0, you gave $x which is less than 0"))
end
end
That’s a good idea, I was thinking more about trying to give the context in which the error occurred. I guess the two are intertwined, but yours is more terse
printing this may spam multiple screen (now you may want an IOBuffer and truncate), or it may even error (display wasn’t implemented properly). This is probably doable for <:Array but it’s I guess people didn’t have time to specialize polish the errors.
Maybe one could argument a replacement of Collection → argument of only(), but I assume the line number of the error message already tells you it’s the only()…
btw, there is a special case for Tuple. The <:Array is just hitting a fallback of trying to iterate() and see if the result is nothing or not.
julia> only((1,2))
ERROR: ArgumentError: Tuple contains 2 elements, must contain exactly 1 element
Stacktrace:
So yeah, I suppose you’re saying we should add a <:Array speailized error message
This thread is not about just only, that was a handy example I had. But in general about strategies to write good errors in the face of uncertainty of values in generic functions. It’s kind of annoying that this aspect suffers so much when writing generic code.
I think the composable way it can work is by calling the show methods for the arguments involved in the showerror method for the error, rather than interpolating into a string as is commonly done, which is divorced from the io context and relies on the string method. Then, if an object supports a reasonable printing vía show, the error can use the that. ArgCheck.jl does this in it’s macros IIRC (though you don’t need a macro to do so).