A while back I came across @npalardy’s blog post Code for safety (best read that post first before you read on). And because I’ve made the error of not clearing flags a few times myself, I adopted his code for my own projects.
Yesterday I needed to create some new flags in a window, and I thought “Really, do I have to do the whole setup again?”. To create a SetFlag
and a ClearFlag
method for each flag and then pass these as delegates to that flipper class becomes a bit cumbersome with time. And clutters your code with all those set and clear methods. So I thought about how I could improve the whole setup.
What I came up with is a class called CodeBlocker
, which serves as the flipper and the actual flag. All you have to do to set up a flag with this class is:
- In the window/class/module create a flag property, e.g.
There is no need to initialize this property as this is done automatically as needed by the flipper.myFlag as CodeBlocker
- In whichever method(s)/event(s) you want to activate the flag, type something like
This will set the flag and automatically clear it whendim flipper as new CodeBlocker(myFlag) #pragma Unused flipper
flipper
is destroyed. - Wherever you need to query the status of the flag type
if CodeBlocker.IsActive(myFlag) then ... end if
How the class works
The class contains a private property for the actual flag. I don’t use a Boolean property here, because in some weird circumstances—when a flag gets set in more than one method coupled with some bad design or an unfortunate chain of events on Xojo’s part—the flag may get cleared prematurely. So instead of a Boolean I use an Integer counter which will be increased when the flag is “set”, and decreased when the flag is “cleared”.
To manipulate the counter I use the fact that a class can access private properties of other instances of the same class. This is done when you instantiate a new flipper or when it is destroyed. This is also the point where the flag is instantiated (if it isn’t already).
The shared method IsActive
checks if a) the flag is not nil
and b) the counter is >0
. Only if both checks are true
the flag is considered set.
The code
Class CodeBlocker
Private Sub Constructor()
// This constructor is made private so that we can't instantiate a flipper
// without a reference to an actual flag
End Sub
Sub Constructor(ByRef flag as CodeBlocker)
if (flag Is nil) then
// Because the "flag" parameter is defined as "ByRef",
// the flag property of the class/module is instantiated
// by this
flag = new CodeBlocker
end if
flag.mCounter = flag.mCounter + 1
self.mFlag = new WeakRef(flag)
End Sub
Private Sub Destructor()
if (self.mFlag Is nil) or (self.mFlag.Value Is nil) then
return
end if
dim flag as CodeBlocker = CodeBlocker(self.mFlag.Value)
flag.mCounter = flag.mCounter - 1
End Sub
Shared Function IsActive(flag as CodeBlocker) as Boolean
return not (flag Is nil) and (flag.mCounter > 0)
End Function
Private Property mCounter as Integer
Private Property mFlag as WeakRef
End Class
Let me know what you think. Useful or not, you decide.
This code is free for all to use, share and modify.
This code is given “as is”. No warranty is given in any form.