Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making "trace" optimise away like "assert"?

GHC rewrites asserts when optimising as just id. Or alternatively, it's behaviour can be changed with a compiler flag. However, I noticed the same doesn't happen with trace. Is there a version of trace which just ends up as id if a flag isn't or is set?

More generally speaking, is there a way to alter the behaviour of a function based on the compiler flags used to compile the calling module (not the flags used to compile itself). Much like assert does. Or is this GHC magic that can only happen with assert?

like image 361
Clinton Avatar asked Nov 22 '16 05:11

Clinton


People also ask

What is assert in embedded?

Asserts are used primarily to validate that the code you or others on your team write is behaving correctly. Asserts should generally not be used when you are trying to validate code from other developers. You should check return values, validate them, and if they are invalid, raise errors or error codes.

Does assert stop program?

An assert statement consists of the assert keyword, the expression or condition to test, and an optional message. The condition is supposed to always be true. If the assertion condition is true, then nothing happens, and your program continues its normal execution.

What is Debug assert?

Assert(Boolean, Debug+AssertInterpolatedStringHandler) Checks for a condition; if the condition is false , outputs a specified message and displays a message box that shows the call stack.

What is trace assert C#?

Assert(Boolean, String) evaluates the condition. If the result is false , it sends the specified diagnostic message to the Listeners collection. You can customize this behavior by adding a TraceListener to, or removing one from, the Listeners collection.


2 Answers

No, at least not based on assert. The magic for assert works the other direction and replaces the identity function with an assertion.

Here's assert from base 4.9:

-- Assertion function.  This simply ignores its boolean argument.
-- The compiler may rewrite it to @('assertError' line)@.

-- | If the first argument evaluates to 'True', then the result is the
-- second argument.  Otherwise an 'AssertionFailed' exception is raised,
-- containing a 'String' with the source file and line number of the
-- call to 'assert'.
--
-- Assertions can normally be turned on or off with a compiler flag
-- (for GHC, assertions are normally on unless optimisation is turned on
-- with @-O@ or the @-fignore-asserts@
-- option is given).  When assertions are turned off, the first
-- argument to 'assert' is ignored, and the second argument is
-- returned as the result.

--      SLPJ: in 5.04 etc 'assert' is in GHC.Prim,
--      but from Template Haskell onwards it's simply
--      defined here in Base.lhs
assert :: Bool -> a -> a
assert _pred r = r
like image 113
Cirdec Avatar answered Oct 16 '22 18:10

Cirdec


OK, back at my computer and finally remembered I wanted to demonstrate this. Here goes:

import Control.Exception
import Debug.Trace
import Control.Monad

traceDebug :: String -> a -> a
traceDebug msg = assert (trace msg True)

main :: IO ()
main = replicateM_ 2 $ do
    print $ traceDebug "here1" ()
    print $ traceDebug "here2" ()
    print $ traceDebug "here3" ()

When compiled without optimizations, the output is:

here1
()
here2
()
here3
()
()
()
()

With optimizations:

()
()
()
()
()
()

So I think this addresses the request, with the standard caveat around trace that once the thunk has been evaluated, it won't be evaluated a second time (which is why the messages only happen the first time through the do-block).

like image 5
Michael Snoyman Avatar answered Oct 16 '22 19:10

Michael Snoyman