HiveBrain v1.2.0
Get Started
← Back to all entries
patternModerate

Higher Order Functions in VBA, the dirty way

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
orderthewayhighervbafunctionsdirty

Problem

I have been building a small library of VBA functions. I have a small section with higher order functions that I'd like to share. It uses strings as delegates/function pointers and Application.Run to actually call the functions.

This isn't by any means a true implementation; just a quick and dirty implementation without connecting external libraries or creating objects for every function. I haven't found real drawbacks yet. Application.Run always passes arguments by value, which would be a draw back, but is desirable in all of these implementations. Also not being able to declare lambdas is a buzz-kill.

Public Sub Map(ByVal delegate As String, ByRef sequence As Variant)

    Dim i As Long
    For i = LBound(sequence) To UBound(sequence)

        sequence(i) = Application.Run(delegate, sequence(i))

    Next i

End Sub
Public Function Mapped(ByVal delegate As String, ByVal sequence As Variant) As Variant

    Mapped = sequence
    Map delegate, Mapped

End Function
Public Function Fold(ByVal delegate As String, ByVal sequence As Variant, _
                     ByVal initial_value As Variant) As Variant

    Fold = initial_value

    Dim el As Variant
    For Each el In sequence

        Fold = Application.Run(delegate, Fold, el)

    Next el

End Function
Public Function Reduce(ByVal delegate As String, ByVal sequence As Variant) As Variant

    ' Head and Tail return the first element and the rest, respectively.
    Reduce = Fold(delegate, Tail(sequence), Head(sequence))

End Function
Public Function Compose(ByVal delegates As Variant, ByVal initial_value As Variant) As Variant

    Compose = initial_value

    Dim delegate As Variant
    For Each delegate In delegates

        Compose = Application.Run(delegate, Compose)

    Next delegate

End Function

Solution

Things I like

  • This idea.



  • You've explicitly declared ByVal and ByRef.



  • All methods are short, clear, and concise.



Things to watch out for

  • All of these functions take variants in as parameters, by necessity. Client code runs the risk of passing in a sequence that isn't enumerable. These really need a comment and maybe a VB_Description attribute describing what kind of arguments the functions expect.



  • You also may want to consider handling runtime error 438 "Object doesn't support Method" for the functions that use For Each loops. There's not much you can do other than return a more meaningful error message though.



  • If you change the loop in Map to a For Each and manually increment i, all of the functions will be compatible with collections as well as arrays.



Nitpicks

  • Underscores have a special meaning. They indicate event procedures. So I would change initial_value to initialValue.



  • While I quickly understood that el stood for element, there's no reason not to just spell it out.

Context

StackExchange Code Review Q#60083, answer score: 12

Revisions (0)

No revisions yet.