Assert statement: Difference between revisions
mNo edit summary |
m (add 7.7 Info expression support) |
||
(9 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
The <var>Assert</var> statement tests a condition. A false condition can send diagnostic | |||
information to the terminal output and audit trail, and/or it can result in cancellation | |||
of the <var class="product">[[SOUL]]</var> request. | |||
==Syntax== | |||
<p class="syntax"><span class="literal">Assert </span><span class="term">cond</span><span class="squareb"> [</span><span class="literal">, </span><span class="squareb">[</span><span class="literal">Snap</span><span class="squareb">] [</span><span class="literal">Info </span><span class="term">info</span><span class="squareb">] [</span><span class="literal">Continue</span><span class="squareb">] ]</span> | |||
</p> | |||
===Syntax terms=== | |||
<table> | |||
<tr><th>cond</th> | |||
<td>The conditions that are being asserted as true. These conditions have exactly the same syntax as conditions on <var>IF</var> statements.</td></tr> | |||
<tr><th><var>Snap</var></th> | |||
<td>Indicates a CCASNAP is to be taken on an assertion failure. A CCASNAP is taken in addition to, but before, any <var class="product">[[SirFact]]</var> dump associated with the assertion failure.</td></tr> | |||
<tr><th><var>Info</var></th> | |||
<td>Extra information that is included in the audit trail and terminal output for the assertion failure as part of an MSIR.0494 message. | |||
<p> | |||
If <var class="term">info</var> is a %variable, the contents of the indicated variable is output. If <var class="term">info</var> contains spaces or other <var class="product">Model 204</var> separator characters, it must be enclosed in quotes. If <var class="term">info</var> is not a %variable and is not enclosed in quotes, the uppercased literal string is output. </p> | |||
<p> | |||
As of version 7.7, <var class="term">info</var> can also be any valid SOUL expression, including a SOUL OO method call, $function, or even a [[Local methods#Defining and invoking a local method|local function]]. The expression, which must be enclosed in parentheses, is evaluated only in the case of an <var>Assert</var> failure. See the "Examples" section, below.</p></td></tr> | |||
<tr><th><var>Continue</var></th> | |||
<td>Indicates that an assertion failure does not cause the request to be cancelled. An MSIR.0494 message, and possibly a <var class="product">SirFact</var> dump, will still be produced, but the request continues.</td></tr> | |||
</table> | |||
==Examples== | |||
Some valid <var>Assert</var> statements are: | |||
<p class="code">assert (%x gt 0) and (%name ne <nowiki>''</nowiki>) | |||
assert %x gt 0, snap | |||
assert not $setg('name', 'value') | |||
assert %x = 22, info %x | |||
assert %x, info 'zero %x' snap | |||
assert %income gt 10000, continue | |||
assert %income gt 10000000, info highroller continue | |||
assert %x gt 0, info ('abc' with 'def') | |||
assert %ls ne "22", info ((%x:a with ' xxx ' with %x:a):right(50, pad='*')) | |||
</p> | |||
<blockquote class="note"> | |||
<p><b>Note:</b> A %variable in the <var>Info</var> clause is interpreted to mean the contents of the indicated variable. For example, the fourth <var>Assert</var> statement | |||
above (<code>assert %x = 22, info %x</code>) produces the following message if <code>%x</code> is 21: </p> | |||
<p class="output">MSIR.0494: Assert info: 21</p> | |||
<p> | |||
In the next-to-last example above, if the <var>Info</var> argument was simply <code>info ( </code>, the <var>Assert</var> would fail to compile in version 7.7 and higher because it had no closing parenthesis. But prior to 7.7, the compiler does not consider expressions, and the statement compiles without error. </p> | |||
<p> | |||
Also, be aware that an error in an expression in the <var>Info</var> clause might only be noticed upon an <var>Assert</var> failure. For example, in the last <var>Assert</var> statement example above, if the 50 in the <var>Right</var> function is changed to <code>-50</code>, and the <var>Assert</var> check fails, you get a message about an error in the <var>Right</var> function instead of an <var>Assert</var> failure message.</p></blockquote> | |||
==Usage notes== | |||
<ul> | |||
<li>An <var>Assert</var> statement uses the same expression handler as the <var>If</var> statement, so it is exactly as efficient as an <var>If</var> statement with the same conditions. </li> | |||
<li>To use an <var>Assert</var>, simply place it before any code that depends on some assumptions | |||
about variables or the environment. <var>Assert</var> statements should be coded to test values | |||
or relationships that are required for the code to run correctly but whose values are not immediately apparent from the surrounding code. | |||
In addition to catching coding errors, the <var>Assert</var> statement provides the following benefits: | |||
<ul> | |||
<li>It makes clear to anyone scanning the program the assumptions on which the code depends. This makes it easier to understand the surrounding code. Similarly, it makes the environmental requirements clear to someone wanting to reuse a code fragment or call a common subroutine. While these benefits can be achieved with comments, the <var>Assert</var> statement has the added benefit that it enforces the restrictions. </li> | |||
<li>It eliminates doubt when you are scanning code trying to debug a problem, and it prevents wasted time on "what if" scenarios that can be ruled out with a simple <var>Assert</var>. </li> | |||
</ul></li> | |||
</ul> | |||
==Discussion== | |||
Programming errors often cause symptoms that point directly to the error. For example, | Programming errors often cause symptoms that point directly to the error. For example, | ||
an incorrectly coded array assignment might result in a subscript range error on the very | an incorrectly coded array assignment might result in a subscript range error on the very | ||
Line 5: | Line 78: | ||
kinds of programming errors are generally easy to isolate and fix, and they are usually | kinds of programming errors are generally easy to isolate and fix, and they are usually | ||
caught during adhoc debugging or fairly quickly after a program goes into production. | caught during adhoc debugging or fairly quickly after a program goes into production. | ||
Yet many other programming errors can cause more subtle problems that cause | Yet many other programming errors can cause more subtle problems that cause | ||
completely unrelated statements to fail, or even cause corruption of data that might not | completely unrelated statements to fail, or even cause corruption of data that might not | ||
Line 14: | Line 87: | ||
data. The code may execute but produce invalid results, or perhaps it may set values | data. The code may execute but produce invalid results, or perhaps it may set values | ||
incorrectly that can cause problems in yet another part of the code. | incorrectly that can cause problems in yet another part of the code. | ||
There are several ways to deal with this problem with assumptions: | There are several ways to deal with this problem with assumptions: | ||
* Don't make assumptions in code. While it is an admirable goal to make code as flexible as possible, taken to the extreme, this approach produces code that is bloated by instructions to handle cases that never happen, setting return codes and status values that should never be set that then have to be checked elsewhere. Put another way, code has to do not only what is necessary but also has to perform many unnecessary tasks. | * Don't make assumptions in code. While it is an admirable goal to make code as flexible as possible, taken to the extreme, this approach produces code that is bloated by instructions to handle cases that never happen, setting return codes and status values that should never be set that then have to be checked elsewhere. Put another way, code has to do not only what is necessary but also has to perform many unnecessary tasks. | ||
* Ignore the problem and hope for the best. | * Ignore the problem and hope for the best. | ||
* Check key assumptions in code, and terminate the program with appropriate diagnostics to isolate the cause of the termination. | * Check key assumptions in code, and terminate the program with appropriate diagnostics to isolate the cause of the termination. | ||
The last solution looks the most appealing. However, without the <var>Assert</var> statement, | The last solution looks the most appealing. However, without the <var>Assert</var> statement, | ||
collecting the appropriate diagnostic information can only be done in User Language, so | collecting the appropriate diagnostic information can only be done in User Language, so | ||
it can be tedious (numerous | it can be tedious (numerous <var>Audit</var>, <var>Print</var>, or <var>$Setg</var> statements), and it still provides | ||
only limited information. | only limited information. | ||
The Sirius Mods provides | The <var class="product">Sirius Mods</var> provides the <var class="product">User Language</var> <var>Assert</var> statement to get around these problems. The <var>Assert</var> statement serves three functions: | ||
problems. The <var>Assert</var> statement serves three functions: | |||
* It tests the validity of an assumption. | * It tests the validity of an assumption. | ||
* It causes the current request to be cancelled if the assumption is incorrect. In an APSY subsystem, this causes transfer to the subsystem error procedure. | * It causes the current request to be cancelled if the assumption is incorrect. In an APSY subsystem, this causes transfer to the subsystem error procedure. | ||
* It indicates the procedure and line number containing the failing <var>Assert</var> statement. | * It indicates the procedure and line number containing the failing <var>Assert</var> statement. Furthermore, in the presence of appropriate <var>[[SIRFACT command#SIRFACT MAXDUMP|SIRFACT MAXDUMP]]</var> and <var>[[SIRFACT command#SIRFACT DUMP|SIRFACT DUMP]]</var> settings, it causes the creation of a <var class="product">SirFact</var> dump that contains a wide variety of information about the program environment at the time of the error. | ||
Stated another way, the <var>Assert</var> statement allows testing of assumptions and extensive | Stated another way, the <var>Assert</var> statement allows testing of assumptions and extensive | ||
diagnostic data collection with a single, simple statement. | diagnostic data collection with a single, simple statement. | ||
[[Category:User Language statements]] | [[Category:User Language statements]] |
Latest revision as of 00:52, 31 August 2016
The Assert statement tests a condition. A false condition can send diagnostic information to the terminal output and audit trail, and/or it can result in cancellation of the SOUL request.
Syntax
Assert cond [, [Snap] [Info info] [Continue] ]
Syntax terms
cond | The conditions that are being asserted as true. These conditions have exactly the same syntax as conditions on IF statements. |
---|---|
Snap | Indicates a CCASNAP is to be taken on an assertion failure. A CCASNAP is taken in addition to, but before, any SirFact dump associated with the assertion failure. |
Info | Extra information that is included in the audit trail and terminal output for the assertion failure as part of an MSIR.0494 message.
If info is a %variable, the contents of the indicated variable is output. If info contains spaces or other Model 204 separator characters, it must be enclosed in quotes. If info is not a %variable and is not enclosed in quotes, the uppercased literal string is output. As of version 7.7, info can also be any valid SOUL expression, including a SOUL OO method call, $function, or even a local function. The expression, which must be enclosed in parentheses, is evaluated only in the case of an Assert failure. See the "Examples" section, below. |
Continue | Indicates that an assertion failure does not cause the request to be cancelled. An MSIR.0494 message, and possibly a SirFact dump, will still be produced, but the request continues. |
Examples
Some valid Assert statements are:
assert (%x gt 0) and (%name ne '') assert %x gt 0, snap assert not $setg('name', 'value') assert %x = 22, info %x assert %x, info 'zero %x' snap assert %income gt 10000, continue assert %income gt 10000000, info highroller continue assert %x gt 0, info ('abc' with 'def') assert %ls ne "22", info ((%x:a with ' xxx ' with %x:a):right(50, pad='*'))
Note: A %variable in the Info clause is interpreted to mean the contents of the indicated variable. For example, the fourth Assert statement above (
assert %x = 22, info %x
) produces the following message if%x
is 21:MSIR.0494: Assert info: 21
In the next-to-last example above, if the Info argument was simply
info (
, the Assert would fail to compile in version 7.7 and higher because it had no closing parenthesis. But prior to 7.7, the compiler does not consider expressions, and the statement compiles without error.Also, be aware that an error in an expression in the Info clause might only be noticed upon an Assert failure. For example, in the last Assert statement example above, if the 50 in the Right function is changed to
-50
, and the Assert check fails, you get a message about an error in the Right function instead of an Assert failure message.
Usage notes
- An Assert statement uses the same expression handler as the If statement, so it is exactly as efficient as an If statement with the same conditions.
- To use an Assert, simply place it before any code that depends on some assumptions
about variables or the environment. Assert statements should be coded to test values
or relationships that are required for the code to run correctly but whose values are not immediately apparent from the surrounding code.
In addition to catching coding errors, the Assert statement provides the following benefits:
- It makes clear to anyone scanning the program the assumptions on which the code depends. This makes it easier to understand the surrounding code. Similarly, it makes the environmental requirements clear to someone wanting to reuse a code fragment or call a common subroutine. While these benefits can be achieved with comments, the Assert statement has the added benefit that it enforces the restrictions.
- It eliminates doubt when you are scanning code trying to debug a problem, and it prevents wasted time on "what if" scenarios that can be ruled out with a simple Assert.
Discussion
Programming errors often cause symptoms that point directly to the error. For example, an incorrectly coded array assignment might result in a subscript range error on the very statement with the error. Alternatively, an assignment from the wrong variable to a screen item results in incorrect data appearing in the corresponding screen field. These kinds of programming errors are generally easy to isolate and fix, and they are usually caught during adhoc debugging or fairly quickly after a program goes into production.
Yet many other programming errors can cause more subtle problems that cause completely unrelated statements to fail, or even cause corruption of data that might not be detected until long after the original error has occurred. This often happens because much code depends on assumptions about the current environment, including assumptions about values of variables. A coding error or a misunderstanding of the environmental requirements of a chunk of code can cause the code to be run with invalid data. The code may execute but produce invalid results, or perhaps it may set values incorrectly that can cause problems in yet another part of the code.
There are several ways to deal with this problem with assumptions:
- Don't make assumptions in code. While it is an admirable goal to make code as flexible as possible, taken to the extreme, this approach produces code that is bloated by instructions to handle cases that never happen, setting return codes and status values that should never be set that then have to be checked elsewhere. Put another way, code has to do not only what is necessary but also has to perform many unnecessary tasks.
- Ignore the problem and hope for the best.
- Check key assumptions in code, and terminate the program with appropriate diagnostics to isolate the cause of the termination.
The last solution looks the most appealing. However, without the Assert statement, collecting the appropriate diagnostic information can only be done in User Language, so it can be tedious (numerous Audit, Print, or $Setg statements), and it still provides only limited information. The Sirius Mods provides the User Language Assert statement to get around these problems. The Assert statement serves three functions:
- It tests the validity of an assumption.
- It causes the current request to be cancelled if the assumption is incorrect. In an APSY subsystem, this causes transfer to the subsystem error procedure.
- It indicates the procedure and line number containing the failing Assert statement. Furthermore, in the presence of appropriate SIRFACT MAXDUMP and SIRFACT DUMP settings, it causes the creation of a SirFact dump that contains a wide variety of information about the program environment at the time of the error.
Stated another way, the Assert statement allows testing of assumptions and extensive diagnostic data collection with a single, simple statement.