Thursday, May 23, 2013

Handling parameters dynamically with Dictionary data structure

Have you ever been having a dream, that sometimes you would like to get rid of all specific input arguments in your function interface?

I mean, instead of this:
Public Function calc(Byval a1 As Double, Byval a2 As Double, ... , Byval n As Double) As Double

you could have this:
Public Function calc(Byref parameters As someDataStructure) As Double

Keep on dreaming, you got company here. I would like to share one approach what I have been using for some time.

The problem

Let us say, that we are going to use VBA Interface mechanism in our program. Let us also think, that our public interface is having only one public function to be implemented. In this case, we need to have homogenous public function interface for all implementations created from it. But what happens, if I would like use different set of input parameters for each interface function implementation?

The solution

One solution for this problem is to wrap all your specific input parameters inside some data structure, like Trojan horse. Then, instead of having n specific input arguments defined in your public function interface, you just have one data structure as your single input argument. The upside of this approach is, that there can be any number of specific parameters inside that data structure.

This approach does not necessarily make your life easier, but more importantly it can enable these (IMHO) more flexible program designs. Note: at this point, you should be well familiar with VBA Enumerators and Microsoft Scripting Runtime library’s Dictionary object. If you feel unsure with these or you need some brush-up, there is a lot of information to be found in Google.

Example

The following program calculates a price for simple non-cashflow paying forward, by using conventional VBA approach by giving all specific parameters separately in a function interface:

Option Explicit
'
Sub tester()
    '
    Debug.Print forwardPrice(100, 0.02, 1.25)
End Sub
'
Private Function forwardPrice(ByVal spot As Double, _
ByVal rate As Double, ByVal maturity As Double) As Double
    '
    forwardPrice = spot * Exp(rate * maturity)
End Function
'
 

There is absolutely nothing wrong with this approach. But, just for the curious .. how could you get rid of these three parameters we are using in that function interface? Just put everything inside Dictionary data structure. We can define distinct Key-Value pairs inside Dictionary object. In our example case, the Key is Enumerator value (spot, rate, maturity) and the Value is a double (100, 0.02, 1.25). For using this approach, we need to have a separate Enumerator data structure for all possible Keys what we would like to use in our parameter wrapper. Just for our example case, Enumerator would look like this:

Option Explicit
'
Public Enum Variable
    spot
    rate
    maturity
End Enum
'
 

The following program calculates a price for simple non-cashflow paying forward, by using that data structure approach by giving all three specific parameters wrapped inside data structure in a function interface:


Option Explicit
'
Sub tester()
    '
    Dim p As New Scripting.Dictionary
    p.Add Variable.spot, 100
    p.Add Variable.rate, 0.02
    p.Add Variable.maturity, 1.25
    Debug.Print forwardPrice(p)
    Set p = Nothing
End Sub
'
Private Function forwardPrice(ByRef p As Scripting.Dictionary) As Double
    '
    forwardPrice = p.Item(Variable.spot) * _
    Exp(p.Item(Variable.rate) * p.Item(Variable.maturity))
End Function
'

Now, what if we need to have more than these three input parameters for some specific implementation? First we need to add more "Keys" to our enumerator. Then we just wrap all our specific parameters into a new Scripting.Dictionary object.

So, that was all I wanted to show about this issue. Personally, I find this approach to be extremely flexible for designs where I would like to use VBA interfaces. The downside is, that you need to have that Enumerator data structure and it needs some babysitting. This Enumerator is a public one and also shared by all modules and classes in your program. Some programmers and authors could definitely find this to be a clear sign of sorcery. For me, it is a price I need to pay to have that flexibility. Also, if you look at the forwardPrice function above, you can see that "disassembling" parameter values from Dictionary object back to program-level is a bit more complicated, than using just plain old separate parameter approach.

I hope, that you got yourself at least some new ideas for your programs. Good luck!
-Mike

No comments:

Post a Comment