Changes between Version 3 and Version 4 of TraceStatement
- Timestamp:
- 12/20/10 02:31:33 (14 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
TraceStatement
v3 v4 1 The ''' assert''' statement is used to verify an expected condition during runtime.1 The '''trace''' statement is a debugging aid to log points of execution in the source code and/or values of expressions. 2 2 3 3 === Grammar === 4 4 {{{ 5 assert <condition>[, <info>] 5 trace 6 trace <expr1>, <expr2>, ... <expr3> 7 trace all 8 trace off 9 trace on 6 10 }}} 7 11 8 If the condition is true, execution proceeds. Otherwise, an '''AssertException''' is raised. Assertions can be turned off at runtime with: 12 A 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 14 When given one or more expressions, '''trace''' gives the same information plus the source code and value of each expression. 15 16 The '''trace all''' statement is a convenience for logging '''this''', every method argument and every local variable. 17 18 The '''trace off''' statement turns off the subsequent trace statements in the declaring method. The '''trace on''' statement turns them back on. 19 20 Sprinkling '''trace''' statements in methods can help diagnose bugs by showing program flow and values during execution, as seen here: 21 9 22 {{{ 10 23 #!cobra 11 CobraCore.willCheckAssert = false 24 class 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 {{{ 36 trace: this=Foo; x=2; y=4; at Foo.cobra:10; in Foo.computeStuff 37 trace: this=Foo; _z=8; at Foo.cobra:11; in Foo.computeStuff 12 38 }}} 13 39 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: 40 An alternative to a trace would be a print statement: 23 41 {{{ 24 42 #!cobra 25 assert obj.foo > bar, 'obj=[obj], obj.foo=[obj.foo], bar=[bar]' 43 ... 44 print 'trace: x=[x]; y=[y]' 26 45 }}} 27 46 28 This is sufficient: 47 But that won't report source information such as line number, and writing such a print statement is more work than: 48 29 49 {{{ 30 50 #!cobra 31 assert obj.foo > bar 51 trace x,y 32 52 }}} 33 53 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.54 Also, '''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. 35 55 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). 56 Note that the '''trace''' statement is backed by a supporting class called '''Tracer''': 37 57 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.40 58 {{{ 41 59 #!cobra 42 # Example 1 43 assert x > y 60 class Tracer 61 inherits Object 62 """ 63 Used to implement the trace statement. 64 """ 44 65 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 """ 47 70 48 # Example 3 49 assert customers.count # as in, the count is not zero 71 cue init(dest as System.IO.TextWriter) 50 72 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 53 105 }}} 106 107 You 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 119 Don'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'''.