implicit call stacks and calling function

I noticed this when I started using the new implicit call stacks feature. I didn't bring it up because I figure it probably had a good reason and was too late to change anyway, but the recent talk about HasCallStack reminded me and I'm curious. When you do GHC.Stack.getCallStack you get a [(String, SrcPos)]. The SrcPos is the position of the calling function, but the String is the callee function. So you can't get the name of the calling function. Instead, you get the name of the function with the call stack annotation. That's not so useful because in say a logging function, I'm interested in the caller's name. I don't need the name of the logging function, it's just something boring like "info" or "warn"! When I switched from a custom preprocessor that sort of implemented SRCLOC_ANNOTATE, it was definitely nice to lose the custom local hackery, but not so nice to lose the caller's name. For tests I used an unsafe mutable global via unsafePerformIO, otherwise failed tests can't report the name of the failing test, but the hack doesn't work for logging. Is there a reason it was done the way it was, or a way to get the name of the calling function?

On Mon, Mar 7, 2016, at 11:35, Evan Laforge wrote:
When you do GHC.Stack.getCallStack you get a [(String, SrcPos)]. The SrcPos is the position of the calling function, but the String is the callee function. So you can't get the name of the calling function. Instead, you get the name of the function with the call stack annotation. That's not so useful because in say a logging function, I'm interested in the caller's name. I don't need the name of the logging function, it's just something boring like "info" or "warn"!
Is there a reason it was done the way it was, or a way to get the name of the calling function?
The reason we provide the name of the callee is that the standard format for a stack trace is callee+pos :) You point about wanting the caller's name too is well-taken though. In most languages you can just look at the next item in the stack to grab the caller, but with HasCallStack there may be no next item... I doubt it would be hard to add the caller's name too, I'd be happy to look into it post-ICFP. Would you mind filing a ticket? Eric

On Mon, Mar 7, 2016 at 11:46 AM, Eric Seidel
The reason we provide the name of the callee is that the standard format for a stack trace is callee+pos :)
I guess it depends how you look at it. I'm used to caller + pos, e.g. in Java: java.lang.RuntimeException: blah blah at com...Caller.caller(Caller.java:494) at ... Or python: Traceback (most recent call last): File "t.py", line 2, in caller def caller(): callee() File "t.py", line 1, in callee def callee(): 1/0 ZeroDivisionError: integer division or modulo by zero The haskell version (reversed to match python) would be like: File "Caller.hs", line 6, in callee caller = callee 10 File "Caller.hs", line 9, in ?stack callee _n = mapM_ print (Stack.getCallStack ?stack) To me this seems off by one, line 6 is in 'caller', not 'callee'.
You point about wanting the caller's name too is well-taken though. In most languages you can just look at the next item in the stack to grab the caller, but with HasCallStack there may be no next item... I doubt it would be hard to add the caller's name too, I'd be happy to look into it post-ICFP. Would you mind filing a ticket?
Done: https://ghc.haskell.org/trac/ghc/ticket/11686 In it I suggested adding a Stack.getFrames :: [Stack.Frame], Frame could then have callee and srcloc fields as per getCallStack's pairs, and add a caller field. Just a suggestion. Thanks so much!

On Mon, Mar 7, 2016, at 15:36, Evan Laforge wrote:
On Mon, Mar 7, 2016 at 11:46 AM, Eric Seidel
wrote: The reason we provide the name of the callee is that the standard format for a stack trace is callee+pos :)
I guess it depends how you look at it. I'm used to caller + pos, e.g. in Java:
java.lang.RuntimeException: blah blah at com...Caller.caller(Caller.java:494) at ...
Or python:
Traceback (most recent call last): File "t.py", line 2, in caller def caller(): callee() File "t.py", line 1, in callee def callee(): 1/0 ZeroDivisionError: integer division or modulo by zero
The haskell version (reversed to match python) would be like:
File "Caller.hs", line 6, in callee caller = callee 10 File "Caller.hs", line 9, in ?stack callee _n = mapM_ print (Stack.getCallStack ?stack)
To me this seems off by one, line 6 is in 'caller', not 'callee'.
Huh, you're quite right.. I remember checking python's formatting when I originally implemented the feature but I must have misread the stack..
participants (2)
-
Eric Seidel
-
Evan Laforge