Assertions in Basic+
Published 16 SEP 2016 at 03:09:46PM
For those of you who have done any Java or C/C++ programming in the past, assertions may be a familiar programming construct. For those who have not, an assertion is simply a way of embedding tests in your programs to check that a condition is true: if the condition evaluates to false then the program stops to display a message informing you of the failure, and presents a set of choices for dealing with it. Assertions are basically "sanity checks" that you can employ anywhere in your programs to ensure that the state of your data is as you expect it. You should use normal error-handling code for errors you expect; you should use assertions for errors that should never occur.
The $assert() statement
In order to support assertions Basic+ a new statement, "$assert" has been introduced into Basic+. This takes a simple comparison expression as an argument like so:
$assert( a > 3 )
The statement above checks that the value of the variable "a" is greater than 3. If so then the program continues as normal, otherwise an assertion is raised and the assert message displayed. When passing expressions to the $assert statement ensure you keep them simple. The $assert is effectively turned into an "if () else" statement when it is compiled, so the resulting runtime code from the example above looks like this:
if ( a > 3 ) else
Therefore you can only pass what you would legally be able to pass to the normal "if" statement.
The $assert_here statement
This statement is an extension of the normal $assert statement and is used to simply assert without testing for an expression. This is commonly used in an "end else" clause when you enter an unexpected code branch. It has two forms:
- $assert_here
- $assert_here( )
The latter form takes a text string (you don't have to quote it) like so:
if bLen( winID ) then // All good end else // We can't get here amiright? $assert_here( winID is null - how did this happen? ) end
Failed assertions
If the assertion fails you are presented with a message that looks like this: [caption id="attachment_2002" align="aligncenter" width="370"] Assertion message[/caption] It tells you the program name, the line number and the expression that caused the failure and gives you three options for processing:
- Abort - This stops all program execution and returns the system to an idle state. Just as if you had hit the debugger and then immediately closed it.
- Debug - This loads the debugger at the point of the assertion.
- Ignore - This continues the program execution as normal.
There is also a checkbox that allows you to turn off all assertions for the rest of the session. Note that if you are running a program from the system monitor the assertion dialog looks slightly different as we rely on the Windows MessageBox function to display the error instead: [caption id="attachment_2016" align="aligncenter" width="309"] Assertion MessageBox[/caption] As you can see, the "Debug" button is replaced by a "Retry" button, but they both perform the same function. Currently assertion messages will not display outside of event context, due to the fact that the message needs a UI to display, and if called from something like a web-server this would be problematic. In this case assertions are ignored.
Disabling assertions
Assertions present a tidy way to deal with some problems without crashing straight into the debugger, but even so you may not not want your customers to see them in your released code. In this case you ensure they are never executed by using one of the following methods:
Disabling assertions with the SetDebugger() function
The SetDebugger function can be used to programmatically turn assertions on or off at runtime using its "ASSERT" method. This can be used when your application is started, and then turned on later for diagnostic purposes if you wish.
$insert logical // Turn off assertions at runtime call SetDebugger( "ASSERT", FALSE$ ) // Turn assertions back on call SetDebugger( "ASSERT", TRUE$ )
Disabling assertions with the compiler
You can also disable assertions when compiling, in which case the checks are never included in the object code. To do this simply use the NOASSERT token with the #define statement like so:
#define NOASSERT
You can add this to individual programs as you wish, or to an IDE build configuration, or to the compiler IFDEF list itself if you call it manually. (Disclaimer: This article is based on preliminary information and may be subject to change in the final release version of OpenInsight 10).
Comments
At 16 SEP 2016 05:38PM Craig Tildesley wrote:
This is fantastic and a nice step towards TDD. What does it do if the assertion is unassigned?
I would say that if it could output the results of the assertions to a file instead of putting them to a window that would be better then you could run a whole load of tests in one go getting all their results without any extra user interaction. As a further step if the tests could run on compile….Build manager
At 17 SEP 2016 12:12AM Chris Meyer wrote:
How will this impact any debug replacement routine and the option shortcut /hi /he where the debugger is not displayed.
At 17 SEP 2016 03:52PM Captain C wrote:
Shouldn't be a problem to add simple logging, or a callback perhaps - I'll look into that.
It will only check for assigned vars if you ask it to - so you'd do something like this:
$assert( assigned( x ) )And so on.
At 17 SEP 2016 03:56PM Captain C wrote:
It has no impact on the debugger replacement as such - clicking the debug button just executes a debug statement. Would you prefer it to force the debugger enviroment value to "1" before it does so?
At 17 SEP 2016 03:58PM martindrenovac wrote:
excellent - what about IF-this-is-a(matrix) ..
At 17 SEP 2016 04:02PM Captain C wrote:
Sorry Martin - can you clarify that? Are you asking to check if the <em>type </em>of the variable is a dimensioned array? Or something else?
At 19 SEP 2016 08:55AM Craig Tildesley wrote:
I think it would be really useful if you could make it log trips to the debugger when in TDD mode not just as part of an assert statement
At 19 SEP 2016 02:46PM Captain C wrote:
You can do that if you write a debugger intercept proc to handle the logging?