Flags - Temporarily Block Code

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:

  1. In the window/class/module create a flag property, e.g.
    myFlag as CodeBlocker
    
    There is no need to initialize this property as this is done automatically as needed by the flipper.
  2. In whichever method(s)/event(s) you want to activate the flag, type something like
    dim flipper as new CodeBlocker(myFlag)
    #pragma Unused flipper
    
    This will set the flag and automatically clear it when flipper is destroyed.
  3. 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.

2 Likes

No. Just don’t. Both to you and the original article.

  • Don’t do methods that are hundreds of code lines. My rule is less than a screen.
  • Refactor your code so that you can handle the flags either at method and even better at class level. Strategy pattern is your friend.

I totally agree with that.

I don’t really understand what you’re saying here. Both my post and the original article are about a way to make sure you don’t forget to clear a flag. Even in short methods that may be a problem, especially if you add some code that “bails early” at a later point. I’ve fallen into this trap more often than I care to admit…

Can you elaborate?

I try in my newer code to do the core method of a class like this:

if not doSomething then return
if not doSomethingelse then return

or similar. Sometimes I do the error handling on the lower level and sometimes on the main level. But there shouldn’t be a need for a flag at all.

there’s lots of code that will require “flags” of some sort

if you can manage to write all your code without a flag then great
this is just a technique to make sure those flags, when needed, can be done in a way you dont forget to set and clear them for some future iteration of the same code