Wiki

Changes between Version 3 and Version 4 of TraceStatement

Show
Ignore:
Timestamp:
12/20/10 02:31:33 (14 years ago)
Author:
todd.a
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • TraceStatement

    v3 v4  
    1 The '''assert''' statement is used to verify an expected condition during runtime. 
     1The '''trace''' statement is a debugging aid to log points of execution in the source code and/or values of expressions. 
    22 
    33=== Grammar === 
    44{{{ 
    5 assert <condition>[, <info>] 
     5trace 
     6trace <expr1>, <expr2>, ... <expr3> 
     7trace all 
     8trace off 
     9trace on 
    610}}} 
    711 
    8 If the condition is true, execution proceeds. Otherwise, an '''AssertException''' is raised. Assertions can be turned off at runtime with: 
     12A simple '''trace''' gives the filename, line number, declaring class name and declaring method name that the '''trace''' is located in. If the current object's class is a subclass of the declaring class then the subclass name is reported as well. 
     13 
     14When given one or more expressions, '''trace''' gives the same information plus the source code and value of each expression. 
     15 
     16The '''trace all''' statement is a convenience for logging '''this''', every method argument and every local variable. 
     17 
     18The '''trace off''' statement turns off the subsequent trace statements in the declaring method. The '''trace on''' statement turns them back on. 
     19 
     20Sprinkling '''trace''' statements in methods can help diagnose bugs by showing program flow and values during execution, as seen here: 
     21 
    922{{{ 
    1023#!cobra 
    11 CobraCore.willCheckAssert = false 
     24class Foo  
     25 
     26    var _z as int  
     27 
     28    def computeStuff(x as int, y as int) 
     29        if x > y 
     30            trace return  
     31        _z = x * y  
     32        trace all  
     33        trace _z  
     34}}} 
     35{{{ 
     36trace: this=Foo; x=2; y=4; at Foo.cobra:10; in Foo.computeStuff 
     37trace: this=Foo; _z=8; at Foo.cobra:11; in Foo.computeStuff 
    1238}}} 
    1339 
    14 Assertions are useful for catching errors early when they are easier to diagnose. They also enable subsequent code to operate under the condition expressed by the assertion. Furthermore, they are source of technical documentation. 
    15  
    16 The message of the '''!AssertException''' includes information to assist in debugging the assertion including: 
    17  
    18  * the filename and line number where the assert statement appeared 
    19  * the info argument, if provided 
    20  * a full breakdown of the condition's subexpressions and their values 
    21  
    22 The breakdown of the condition is significant because it not only aids troubleshooting, but largely eliminates the need to specify the '''info''' argument. For example, rather than: 
     40An alternative to a trace would be a print statement: 
    2341{{{ 
    2442#!cobra 
    25 assert obj.foo > bar, 'obj=[obj], obj.foo=[obj.foo], bar=[bar]' 
     43... 
     44print 'trace: x=[x]; y=[y]'  
    2645}}} 
    2746 
    28 This is sufficient: 
     47But that won't report source information such as line number, and writing such a print statement is more work than: 
     48 
    2949{{{ 
    3050#!cobra 
    31 assert obj.foo > bar 
     51trace x,y 
    3252}}} 
    3353 
    34 ...because if the assertion fails, the values of '''obj''', '''obj.foo''' and '''bar''' will be given in the exception's '''message'''. Note that reporting the subexpression values causes the subexpressions to execute a second time, so the reported values can be misleading due to side-effects. In practice, this is rare. 
     54Also, '''trace''' statements are easy to locate and remove—or turn off via '''trace off'''—while leaving application '''print''' statements in tact. And '''trace''' output is flushed with each trace, by default. 
    3555 
    36 Developers often disable assertions in production software, presumably for a speed boost. But in practice, the overhead of assert statements is often so small as to not be noticeable. Since assertions offer the benefit of easier failure analysis, they should generally be left on. At the same time, providing a switch to turn them off can be prudent because the assertions themselves can be buggy (meaning the assertion fails, but does indicate an actual problem with the program because the condition was poorly formulated). 
     56Note that the '''trace''' statement is backed by a supporting class called '''Tracer''': 
    3757 
    38 Strongly consider using '''require''' instead of '''assert''' when verifying the state of the object at the very beginning of a method or property, or verifying the state of the parameters.  
    39 Strongly consider using '''ensure''' instead of '''assert''' when verifying the state of the object at the very ending of a method or property, or verifying the state of the return value. 
    4058{{{ 
    4159#!cobra 
    42 # Example 1  
    43 assert x > y  
     60class Tracer  
     61    inherits Object 
     62    """  
     63    Used to implement the trace statement.  
     64    """  
    4465 
    45 # Example 2  
    46 assert node # as in, the node is not nil  
     66    cue init  
     67        """  
     68        Initializes the tracer with Console.out as the destination.  
     69        """  
    4770 
    48 # Example 3  
    49 assert customers.count # as in, the count is not zero  
     71    cue init(dest as System.IO.TextWriter)  
    5072 
    51 # Example 4  
    52 assert name.length  
     73    pro isActive as bool  
     74        """  
     75        When false, the `trace` methods will produce no output.  
     76        """  
     77 
     78    pro willAutoFlush as bool  
     79        """  
     80        When true, `destination.flush` is invoked after every trace.  
     81        Defaults to `true`.  
     82        """  
     83 
     84    pro destination as String  
     85        """  
     86        The TextWriter where all trace output is sent to.  
     87        """  
     88 
     89    pro separator as String  
     90        """  
     91        The separator string used between items of both name/value pairs and source information.  
     92        Default is '; '.  
     93        """  
     94 
     95    pro prefix as String  
     96        """  
     97        The prefix string used at the beginning of every trace.  
     98        Default is 'trace: '.  
     99        """  
     100 
     101    def trace(source as SourceInfo)  
     102 
     103    def trace(source as SourceInfo, nameValues as vari Object) 
     104        require nameValues.length % 2 == 0  
    53105}}} 
     106 
     107You can get access to the current tracer with the shared property, '''CobraCore.tracer'''. In fact, you can use that same property to set the Tracer instance that the trace statements use, although modifying the default instance is normally sufficient. For example: 
     108 
     109{{{ 
     110#!cobra 
     111    class Program  
     112        def main is shared 
     113        tracer = CobraCore.tracer  
     114        tracer.prefix = ''  
     115        tracer.separator = ', '  
     116        tracer.destination = File.createText('trace.text')  
     117}}} 
     118 
     119Don't confuse '''trace on/off''' with '''Tracer.isActive'''. The '''trace on/off''' statements are purely compile-time directives that affect only the method that contains them. The '''Trace.isActive''' property is purely a run-time property and will deactive the output of all trace statements when set to '''false'''.