Continuing the theme of “things I should have learned sooner”, starting with finding out that If/Switch Statements are expensive, I also finally started learning about Delegates. I had heard of them, and I knew what Function Pointers were from C++ way back in 1999. But I can’t believe I hadn’t looked into Delegates sooner, or that none of the tutorials or articles I ever read had forced me to learn them until now.
The timing worked out okay though, because Delegates are useful in writing Branchless code to avoid If Statements. By setting up a Delegate to point to the proper Function beforehand, you can avoid using an If to decide which Function to call every GameLoop.
Here I’ve created a Structure to easily set up a Choice between two or more Functions, using an Array of Actions. An Action is a generic Delegate that points to a Sub (or a Void in C#). In other words a Function with no Parameters and no Return value. I haven’t even started using this technique yet, other than verifying that this code works.
Public Branch() As Action
Public Sub SetupBoolean(_True As Action, _False As Action)
Branch(0) = _False
Branch(1) = _True
Public Sub New(_True As Action)
Public Sub New(_True As Action, _False As Action)
Public Sub New(Actions() as Action)
Branch = Actions
'// Use [Brackets] for names that are already keywords.
Public Sub [If](Comparison As Boolean)
Public Sub [Call](Index As Integer)
Public Property Yes As Action
Set(value As Action)
Branch(1) = value
Public Property No As Action
Set(value As Action)
Branch(0) = value
And here is a very basic example of these Actions in action:
Question.InvokeIf(Nobler > Whatever)
There are three New() declarations to Instantiate a Choice. If you only specify the AddressOf for the True Action, then
InvokeIf(False) will do Nothing. New() also takes an Array of Actions, but I’ll get to that later.
The most notable line of code in the Choice Structure is only line in the
Branch(-Comparison)?.Invoke(), and in particular the “
?.” or “Null-Conditional Operator”. Before I get to that, remember that
-Comparison becomes 0 or 1, which “chooses” from the first two Actions in the Branch Array.
Then the “
?.“, or as I call it the “Hello Operator”, will “ask” the variable if it has been instantiated as New, or is still set to Nothing, AKA Null in C#. If it gets no response, the Statement will “short-circuit” and just move on, the Delegate’s Function (the Action’s Sub in this case) is not Invoked.
This is what allows you to avoid checking
If Branch(-Comparison) IsNot Nothing before Invoking the Delegate. Even a simple If Statement like that is expensive in a GameLoop. There might also be a small cost to set up a Delegate or Action, so it’s not something you want to change every Frame.
AddressOf ToSleepNoMore, AddressOf PerchanceToDream,
Here’s the example of initializing a Choice with an Array of Action Delegates. Then you can use Call(#) to call each Function. I’ll be using this to replace times where I use a Switch Statement to choose a Function based on an ID number, such as the Genus of a Nub, or the Type of a jeOS Interface Zone.
I’m still pretty surprised I hadn’t learned this sooner, but I’m also kinda surprised it’s not built-in. It’s pretty easy to implement yourself though, and you might want to do things differently. For instance, you could add Functions specific to your game that use an Enumerator to reference which Branch to Invoke.
This way, when you go to call
IfGenus(, the list of items in the Genus Enumerator would show up in AutoComplete as soon as you hit “(“.