Use of errorWithoutStackTrace in the Prelude

Hello, I noticed that the partial functions in the Prelude use errorWithoutStackTrace instead of `error` to provide their error messages, which produces significantly worse error messages. I stumbled into this when a coworker of mine had trouble tracking down a use of `head` that was throwing an exception, but didn’t include any information about where it was in the source. What exactly is the rationale for this? Is it to avoid the performance penalty of passing around the implicit parameter? That seems relatively unlikely, since the performance hit seems trivial, but perhaps it’s to avoid breaking tests that depend on error messages? I think it would be nice for Prelude-provided functions to be informative by default, so the change seems worth it to me, but I’m wondering if there’s something I’ve overlooked. Also, if the answer really is “no, errorWithoutStackTrace is correct”, is the expectation that people will use -prof if they want stacks? This seems a bit frustrating to a newcomer who might not understand anything more complicated than running `stack test` and might not be able to figure out how to pass the right options (especially since options need to be passed both at compile-time and at runtime). Thanks, Alexis

The performance impact is part of the rationale, but a bigger issue is the burden on the type signatures. Using the new `error` would not be enough to get useful locations for `head` and friends. The stack trace would only contain the call to error *inside* head, and not the call to head itself, which is pure noise. If we wanted to add the call to head, we would have to add a `HasCallStack` constraint to `head` itself (and all other partial functions). We discussed this back when I first implemented the implicit call-stacks, and decided to be conservative with their use in base for these reasons. Though it is worth noting that at this point we were still using an explicit implicit parameter instead of the `HasCallStack` alias, which made the constraint more unfamiliar especially to newcomers. Perhaps with the new alias the API-cluttering concerns are less of a problem. In the meantime, I have a package http://hackage.haskell.org/package/located-base that provides callstack-aware variants of many partial functions that I use, and would happily accept a PR for any others that you use! Eric On Tue, Dec 6, 2016, at 16:30, Alexis King wrote:
Hello,
I noticed that the partial functions in the Prelude use errorWithoutStackTrace instead of `error` to provide their error messages, which produces significantly worse error messages. I stumbled into this when a coworker of mine had trouble tracking down a use of `head` that was throwing an exception, but didn’t include any information about where it was in the source.
What exactly is the rationale for this? Is it to avoid the performance penalty of passing around the implicit parameter? That seems relatively unlikely, since the performance hit seems trivial, but perhaps it’s to avoid breaking tests that depend on error messages? I think it would be nice for Prelude-provided functions to be informative by default, so the change seems worth it to me, but I’m wondering if there’s something I’ve overlooked.
Also, if the answer really is “no, errorWithoutStackTrace is correct”, is the expectation that people will use -prof if they want stacks? This seems a bit frustrating to a newcomer who might not understand anything more complicated than running `stack test` and might not be able to figure out how to pass the right options (especially since options need to be passed both at compile-time and at runtime).
Thanks, Alexis _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Dec 6, 2016, at 21:04, Eric Seidel
wrote: The performance impact is part of the rationale, but a bigger issue is the burden on the type signatures.
Using the new `error` would not be enough to get useful locations for `head` and friends. The stack trace would only contain the call to error *inside* head, and not the call to head itself, which is pure noise. If we wanted to add the call to head, we would have to add a `HasCallStack` constraint to `head` itself (and all other partial functions).
Right, of course; my assumption was that it would be necessary to both add HasCallStack and use `error`, though I figured you would also want to use withFrozenCallStack to prevent the call stack from `error` from bubbling through (since that really is just noise; nobody needs to know the location of `error` inside of base). Upon further inspection, though, I realized errorWithoutStackTrace effectively includes withFrozenCallStack (rather than taking an alternate path that ignores the call stack entirely), so adding the HasCallStack constraint seems like it should be sufficient on its own.
We discussed this back when I first implemented the implicit call-stacks, and decided to be conservative with their use in base for these reasons. Though it is worth noting that at this point we were still using an explicit implicit parameter instead of the `HasCallStack` alias, which made the constraint more unfamiliar especially to newcomers. Perhaps with the new alias the API-cluttering concerns are less of a problem.
Yeah, I could see the potential for confusion here, but IMO the potential gains from offering source locations in error messages by default is a bigger win for beginners than the slightly more complicated type signatures are a loss. That’s obviously just my opinion though, since I have no evidence whatsoever to back that up, but it’s definitely something I’d like to see.
In the meantime, I have a package
http://hackage.haskell.org/package/located-base
that provides callstack-aware variants of many partial functions that I use, and would happily accept a PR for any others that you use!
This is a nice package; thank you for writing it! I’ll definitely keep it in mind, though admittedly, it’s pretty unlikely I’d find it worth it to import just to get the call stacks for a handful of functions I try to avoid whenever possible, anyway (which is why I think these need to be in base to be all that useful — my guess is that beginners are by far the most likely to use partial functions in situations that may throw, and they are unlikely to discover your package). That said, it’s good to have, and I’ll relay its existence to my coworker. Alexis
participants (2)
-
Alexis King
-
Eric Seidel