[GHC] #12096: Attach stacktrace information to SomeException

GHC ghc-devs at haskell.org
Tue Mar 28 18:16:47 UTC 2017


#12096: Attach stacktrace information to SomeException
-------------------------------------+-------------------------------------
        Reporter:  ndtimofeev        |                Owner:  (none)
            Type:  feature request   |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Core Libraries    |              Version:  8.0.1
      Resolution:                    |             Keywords:  Exceptions
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by ekmett):

 Replying to [comment:17 ezyang]:
 > Your wiki page does comment that call stacks are preserved if you
 rethrow SomeException. But this often doesn't happen in practice. For
 example, the `system-fileio` example above rethrows an `IOError`: oops,
 call stack lost.

 Yes, there is no correct way to preserve this information that doesn't
 require the user signalling intent to us. Is what they are throwing a
 truly fresh exception or does it derive from one they were given?

 On the other hand, the very callstack was information you lacked to begin
 with in the old story.

 If we extend SomeException you can write code that is compatible with both
 the old and new story, and you can make a couple of one line tweaks to
 your code to make it so you can preserve the shiny new callstack
 information.

 If we extend _every_ exception type to carry this information then there
 is no code that has ever been written against the exception hierarchy that
 can survive the change. Moreover, the Exception class itself then has to
 provide a means for us to get in and find and replace the callStack in
 these user definable data types, and the user has to construct an empty
 callstack to throw their exception in the first place, all of which seems
 like a messy, invasive, and slow design.

 If we offer some subset of combinators (subject to bikeshedding) like

 {{{#!hs
 throwWithCallStack :: Exception e => e -> CallStack -> a
 withCallStack :: SomeException -> CallStack -> SomeException
 rethrow :: SomeException -> a
 rethrowAs :: Exception => SomeException -> e -> a
 throwIOWithCallStack, rethrowIO, rethrowIOAs ...
 catchWithCallStack :: Exception e => IO a -> (e -> CallStack -> IO a) ->
 IO a
 ...
 }}}

 to the user, then they can fix up these cases as they find them, and in
 the meantime they only get the callstack up to the last `throw`, which is
 __still__ more information than they have today.

 The same scenario involving destroying the source location happens in
 languages like c++ w/ throw vs rethrow.

 I personally am sad that extending `SomeException` with the callstack
 would mean my pretty little prisms into `SomeException` for the various
 exception types become a (convenient) lie, but I don't think the
 alternative of making the user decorate all of their exception types with
 a callstack, mangle every throw so that they include an empty callstack to
 kickstart the exception, and supply a callstack update function, and
 change all of their existing handlers, most of which do not rethrow, to
 deal with an extra argument is a terribly practical alternative.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12096#comment:21>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list