<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, Mar 5, 2016 at 12:23 AM, Michael Sloan <span dir="ltr"><<a href="mailto:mgsloan@gmail.com" target="_blank">mgsloan@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">On Fri, Mar 4, 2016 at 8:30 AM, Eric Seidel <span dir="ltr"><<a href="mailto:eric@seidel.io" target="_blank">eric@seidel.io</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span>On Fri, Mar 4, 2016, at 06:53, Johannes Waldmann wrote:<br>
> Dear Cafe,<br>
><br>
> the new (8.*) call stack feature<br>
> <a href="https://downloads.haskell.org/~ghc/8.0.1-rc2/docs/html/users_guide/glasgow_exts.html#hascallstack" rel="noreferrer" target="_blank">https://downloads.haskell.org/~ghc/8.0.1-rc2/docs/html/users_guide/glasgow_exts.html#hascallstack</a><br>
> is certainly nice for debugging during development.<br>
><br>
> But how costly is it at runtime? I notice a 5 percent slowdown.<br>
<br>
</span>HasCallStack is really just a type class with a couple special rules for<br>
building dictionaries in GHC's constraint solver. So at runtime each<br>
function with a HasCallStack constraint takes an extra CallStack<br>
argument. I don't know how to quantify the performance implications<br>
beyond that, but you're right that HasCallStack is not free.</blockquote><div><br></div></span><div>Hmm, is it no longer an implicit parameter?  I thought the new</div><div>HasCallStack stuff was just a constraint synonym like</div><div><br></div><div>type HasCallStack = (?callStack :: CallStack)</div><div><br></div><div>For the most part the distinction doesn't matter, but it does when it</div><div>comes to constraints in instance heads.  The issue is that constraints</div><div>are not solved at their callsites.  Do we want `HasCallStack` to be</div><div>able to be present in an instance head, and potentially get a location</div><div>quite different from the actual use site?  I would find this confusing,</div><div>though sometimes helpful.</div></div></div></div></blockquote><div><br></div><div>I realized I could answer my own questions simply by trying it out on GHC 8 RC2!</div><div><br></div><div>    instance HasCallStack => Read Void where<br></div><div>      read _ = prettyStack callStack ++ "\nCan't possibly read Void!" </div><div><br></div><div>does indeed produce the error</div><div><br></div><div><div>    • Illegal implicit parameter ‘?callStack::CallStack’</div><div>    • In the context: HasCallStack</div><div>      While checking an instance declaration</div><div>      In the instance declaration for ‘Read Void’</div></div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div></div><div>Implicit parameters are a good match for this callstack stuff, because</div><div>they have the restriction that they cannot be used as supeclass</div><div>constraints.</div><div><br></div><div>Does your work on the callstack stuff (thanks!) introduce backwards</div><div>compatibility issues?  I'm working on a library that will make extensive</div><div>use of 7.10's implementation of callstacks.</div></div></div></div></blockquote><div><br></div><div>I tried it out, and it does have compatibility with the implicit parameter</div><div>still!  Good stuff.</div><div><br></div><div>However, I was making use of a potentially unintentional aspect</div><div>of the 7.10 API, which is that `getCallStack` can be used in a record</div><div>update of `CallStack`.  This is useful for annotating callstacks with</div><div>helpful debugging info, like the arguments used for an invocation.</div><div>The existing format for the message works quite well for this, since</div><div>it's just the function name.  So, appending parameters results in</div><div>"fn a1 a2 a3", etc.</div><div><br></div><div>Is it too late in the GHC release cycle to have add an additional</div><div>GHC.Stack.Internal module which enables modification of CallStack?</div><div><br></div><div>I realize that it might be quite intentional that CallStack can't be modified,</div><div>as that could make it less useful as a source of trustable diagnostic info.</div><div>How about only exposing access to the top:</div><div><br></div><div><div>getCallStackHeadMessage :: CallStack -> Maybe String</div><div>setCallStackHeadMessage :: String -> CallStack</div><div>modifyCallStackHeadMessage :: (String -> String) -> CallStack -> CallStack</div></div><div><br></div><div>Or, if we're feeling lensy</div><div><br></div><div><div>callStackHeadMessage :: Functor f => (String -> f String) -> (CallStack -> f CallStack)</div></div><div><br></div><div>Since only the top can be modified, we can trust that the entries of</div><div>the CallStack are accurate.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span>
> That's not a problem if there's an easy way to switch<br>
> this off for production (without changing the code).<br>
<br>
</span>Since HasCallStack is not a feature of the RTS, but actually part of the<br>
generated code, there's not really an easy way to disable it without<br>
changing the code. As much as I dislike CPP, I think it's the best<br>
solution for a toggleable HasCallStack, something like<br>
<br>
#if DEBUG<br>
#define HASCALLSTACK (HasCallStack)<br>
#else<br>
#define HASCALLSTACK ()<br>
#endif<br>
<br>
foo :: HASCALLSTACK => a -> b<br>
<br>
ought to work.<br>
<span><br>
> Related: how to make code that uses it,<br>
> compile with older ghcs that don't have it.<br>
><br>
> I made this hack: do not import GHC.Stack.Types, but instead<br>
><br>
> {-# language CPP, MultiParamTypeClasses #-}<br>
><br>
> #if (__GLASGOW_HASKELL__ < 710)<br>
> {-# language NullaryTypeClasses #-}<br>
> #endif<br>
><br>
> module Stack<br>
> ( HasCallStack )<br>
> where<br>
><br>
> #if (__GLASGOW_HASKELL__ >= 800)<br>
> import GHC.Stack.Types<br>
> #else<br>
> class HasCallStack<br>
> instance HasCallStack<br>
> #endif<br>
<br>
</span>This might be a nice addition to the base-compat package.<br>
<span><br>
> When I compile with 8.rc2, and change ">= 800" to ">= 900",<br>
> I am getting the 5 percent speedup mentioned above.<br>
><br>
> But does it really do what I hope it does<br>
> (remove all runtime overhead that call stacks may have)?<br>
<br>
</span>It should remove all the overhead of call stacks for calling functions<br>
you wrote. If you import a function with a HasCallStack constraint<br>
there's no way to disable the overhead for that function (for good<br>
reason, it might use the CallStack!).<br>
<span><br>
> When I compile with 7.10.3, I am getting 5 .. 10 percent faster again.<br>
><br>
> My code does nothing fancy (w.r.t. types and libraries),<br>
> it just uses Data.IntMap heavily. And it has some<br>
><br>
> class Semiring s where<br>
>   zero :: s<br>
>   one  :: s<br>
>   plus :: HasCallStack => s -> s -> s<br>
>   times :: HasCallStack => s -> s -> s<br>
<br>
</span>I'm curious, why do plus and times take a CallStack? I wouldn't expect<br>
them to be partial, so it seems like unnecessary overhead.<br>
<span><font color="#888888"><br>
Eric<br>
</font></span><div><div>_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
</div></div></blockquote></div></div><br></div></div>
</blockquote></div><br></div></div>