So I just ran into this while working on an assertion for the REALbasic IDE, and I figured I'd share this with you. I'm assuming that everyone has their own mechanism for dealing with invariants in their code, such as assertions. But if not, here's a little refresher course:
It's never a bad idea to double-check your assumptions in code. If you're assuming that Foo = Bar, then check it. The way most people do this is they make a global method called "Assert" which checks to see if an expression evaluates to false. If it does, then it throws some sort of dialog at the user. The thought is that you should never see assertions since you're asserting that some construct is always true (hence, it's invariant).
For example, let's say you're working with some secure data transmission. The invariant you want to check is that the user is working in secure mode. So you might write your assertion like this:[rbcode]
if Assert( SecurityLevel > 3, "The user's not in secure mode, but we're trying to do secure things." ) then return
[/rbcode]
So this code checks to see if the property SecurityLevel is greater than 3, and if it's not, then it displays a dialog to the user and bails out of the code. It's an easy way to ensure that your assumptions are correct and can save you a lot of headaches.
(Thing to note: assertions are almost always bugs in your code.)
But one thing that's hard to do is track down why the invariant is failing. What is calling that function at the incorrect time or with the incorrect parameters, etc? Here's where my handy tip comes in. You have information available to you which can tell you what code path was used to enter this method: RuntimeException.Stack. Put this code in your Assert method so that the message you display to the user is altered slightly (this code assumes you get a parameter called message as String which is then displayed to the user):
[rbcode]
..
try
raise new RuntimeException
catch err as RuntimeException
message = message + EndOfLine + Join( err.Stack, EndOfLine )
end try
..[/rbcode]
Bingo -- now any time an assertion is thrown, you'll be given information about the call stack which you can then use to help you debug the issue.
Neat and simple, eh?
Is this anything like my floating pallette dissappearing on my second monitor kinda bug?
I use this function in my PDF Classes:
Sub Assert(condition as boolean, message as string)
if not condition then _
raise new PDFFailedAssertionException( message )
End Sub
This has a few advantages:
- You have to deal with the assertion since it's raised as an exception.
- It bails out of code for you.
- You get a stack trace.
- Calling syntax is simple and clear.
- The message can be displayed on an application-specific basis; this is essential for frameworks like my PDF Classes that are used in various applications, most of which are not mine.
It probably has some disadvantages, but I like it :-)
Aaron - Have you tried this in something like an event handler ?
In an effort to make this work as far back as I own I wrote
dim tmp as string
tmp = message
if not condition then
#if RBVersion >= 2006
try
raise new RuntimeException
catch err as RuntimeException
tmp = message + EndOfLine + Join( err.Stack, EndOfLine )
end try
#endif
msgbox "Assertion failed : " + tmp
end if
I put a popupmenu on the windows and agve it an initial of 0 1 2 3 4 5 6
I aded a pushbutton to the window
Then in the pushbutton's action event a wndow I wrote
dim SecurityLevel as integer
SecurityLevel = val(PopupMenu1.text)
if assert(SecurityLevel > 3, "The user's not in secure mode, but we're trying to do secure things." ) then return
Run this with the popup set to 0 and then step in to the assert method
no message and tmp is set to something well .... ick
should I report this ?
@Norman -- I'm unable to reproduce any issue on Windows. You're welcome to report it though (just be sure to double-check you're on 2006 or higher).