3
\$\begingroup\$

Most of the VBA I write is to produce tabulated reports from spreadsheet data.

So, here is my attempt at creating a CLS_Data_Report class.


Properties:

a 2-dimensional Data Array

3 dictionaries to, respectively:

  • Map headers to column indexes

  • Map external (user-set) descriptions to data headers

  • Store number formatting for columns (by header)

And the PrintRange (for other visual formatting, e.g. row-colouring)


Key Methods:

  • Add Data to the Array (options for merging, overwriting, replacing)

  • Create a filtered report based on a single columns' values

  • Print the report to a worksheet (and set number formatting)


What I would especially like to know is, is this a good abstraction? (Is it too high, not high enough, is it trying to do too much, not enough?)

As always, any other feedback is greatly appreciated.


Properties and Class_Initialize

Option Explicit
Private pReportData As Variant '/ Data Array
Private pMapDescriptionsToHeaders As Scripting.Dictionary
Private pColumnIndexesOfHeaders As Scripting.Dictionary
Private pNumberFormatsOfHeaderColumns As Scripting.Dictionary
Private pPrintRange As Range
'/============================================================================================================================================================
Private Sub Class_Initialize()
 pReportData = Array()
 
 Set pMapDescriptionsToHeaders = New Scripting.Dictionary
 Set pNumberFormatsOfHeaderColumns = New Scripting.Dictionary
 Set pColumnIndexesOfHeaders = New Scripting.Dictionary
 
End Sub

Property Get/Set

'/============================================================================================================================================================
Public Property Get printRange() As Range
 Set printRange = pPrintRange
End Property
Public Property Set printRange(ByRef printRange As Range)
 Set pPrintRange = printRange
End Property
'/============================================================================================================================================================
Public Property Get reportData() As Variant
 reportData = pReportData
End Property
Public Property Set reportData(ByRef inputArray As Variant)
 pReportData = inputArray
End Property
'/============================================================================================================================================================
Public Property Get MapDescriptionsToHeaders() As Scripting.Dictionary
 Set MapDescriptionsToHeaders = pMapDescriptionsToHeaders
End Property
Public Property Set MapDescriptionsToHeaders(ByRef descriptions As Scripting.Dictionary)
 Set pMapDescriptionsToHeaders = MapDescriptionsToHeaders
End Property
'/============================================================================================================================================================
Public Property Get NumberFormatsOfHeaderColumns() As Scripting.Dictionary
 Set NumberFormatsOfHeaderColumns = pNumberFormatsOfHeaderColumns
End Property
Public Property Set NumberFormatsOfHeaderColumns(ByRef numberFormats As Scripting.Dictionary)
 Set pNumberFormatsOfHeaderColumns = numberFormats 
End Property
'/============================================================================================================================================================
Public Property Get ColumnIndexesOfHeaders() As Scripting.Dictionary
 Set ColumnIndexesOfHeaders = pColumnIndexesOfHeaders
End Property
Public Property Set ColumnIndexesOfHeaders(ByRef columnIndexes As Scripting.Dictionary)
 Set pColumnIndexesOfHeaders = columnIndexes 
End Property

Main Methods

'/============================================================================================================================================================
Public Sub AddDataToReport(ByRef inputArray As Variant, ByVal mergeArrays As Boolean, Optional ByVal unidHeader As Variant, Optional ByVal overrideValues As Boolean)
 If mergeArrays Then
 If IsMissing(unidHeader) Or IsMissing(overrideValues) Then PrintErrorMessage "Merge Arrays is specified but required arguments are not supplied"
 End If
 If ArrayIsAllocated(pReportData) Then
 WriteDataToArray inputArray, mergeArrays, unidHeader, overrideValues
 Else
 ReplaceDataArray inputArray
 End If
End Sub
Public Sub WriteDataToArray(ByRef inputArray As Variant, ByVal mergeArrays As Boolean, Optional ByVal unidHeader As Variant, Optional ByVal overrideValues As Boolean)
 If mergeArrays Then
 Dim unidRows As Scripting.Dictionary
 Set unidRows = CreateDictOfUnidRowNumbers(inputArray, unidHeader)
 End If
 
 Dim targetArray As Variant
 targetArray = pReportData
 
 '/=========================================================================================================================
 Dim inputLB1 As Long, inputUB1 As Long
 Dim inputLB2 As Long, inputUB2 As Long
 AssignArrayBounds inputArray, inputLB1, inputUB1, inputLB2, inputUB2
 
 Dim inputHeaderRow As Variant
 inputHeaderRow = RowFrom2dArray(inputArray, inputLB1)
 
 '/=========================================================================================================================
 Dim targetLB1 As Long, targetUB1 As Long
 Dim targetLB2 As Long, targetUB2 As Long
 AssignArrayBounds targetArray, targetLB1, targetUB1, targetLB2, targetUB2
 
 Dim targetHeaderRow As Variant
 targetHeaderRow = RowFrom2dArray(targetArray, targetLB1)
 
 '/=========================================================================================================================
 Dim i As Long, j As Long, k As Long
 Dim ix As Long, iy As Long
 
 Dim inputHeader As Variant, targetHeader As Variant
 Dim inputCol As Long, targetCol As Long
 Dim inputRow As Long, targetRow As Long
 Dim inputValue As Variant
 
 If mergeArrays Then
 Dim unid As Variant, unidCol As Long
 unidCol = IndexIn1dArray(inputHeaderRow, unidHeader)
 End If
 
 Dim headerMatchFound As Boolean, addValue As Boolean
 
 '/ Add any missing headers
 For iy = inputLB2 To inputUB2
 inputCol = iy
 inputHeader = inputArray(inputLB1, inputCol)
 
 targetCol = targetLB2 - 1
 headerMatchFound = False
 For i = targetLB2 To targetUB2
 targetHeader = targetArray(targetLB1, i)
 If inputHeader = targetHeader Then
 headerMatchFound = True
 targetCol = i
 Exit For
 End If
 Next i
 
 If Not headerMatchFound Then
 targetUB2 = targetUB2 + 1
 ReDim Preserve targetArray(targetLB1 To targetUB1, targetLB2 To targetUB2)
 targetArray(targetLB1, targetUB2) = inputHeader
 SetColumnIndexOfHeader targetUB2, inputHeader
 targetCol = targetUB2
 End If
 
 Next iy
 
 Set ColumnIndexesOfHeaders = Me.ColumnIndexesFromHeadersInArray(targetArray)
 
 '/ Add Values
 targetHeaderRow = RowFrom2dArray(targetArray, targetLB1)
 targetArray = Transpose2dArray(targetArray)
 
 addValue = True
 For ix = inputLB1 + 1 To inputUB1
 inputRow = ix
 inputValue = inputArray(inputRow, inputCol)
 
 If mergeArrays Then
 
 unid = inputArray(ix, unidCol)
 If Not unidRows.Exists(unid) Then
 targetUB1 = targetUB1 + 1
 ReDim Preserve targetArray(targetLB2 To targetUB2, targetLB1 To targetUB1)
 targetRow = targetUB1
 Else
 targetRow = unidRows.item(unid)
 End If
 
 addValue = Not (IsEmptyNothingOrNull(inputValue) And overrideValues)
 Else
 addValue = True
 targetUB1 = targetUB1 + 1
 ReDim Preserve targetArray(targetLB2 To targetUB2, targetLB1 To targetUB1)
 targetRow = targetUB1
 End If
 
 If addValue Then
 For iy = inputLB2 To inputUB2
 inputCol = iy
 inputHeader = inputArray(inputLB1, inputCol)
 targetCol = ColumnIndexesOfHeaders.item(inputHeader)
 
 inputValue = inputArray(inputRow, inputCol)
 targetArray(targetCol, targetRow) = inputValue
 Next iy
 End If
 Next ix
 targetArray = Transpose2dArray(targetArray)
 pReportData = targetArray
End Sub
'/============================================================================================================================================================
Public Sub PrintToWorksheet(ByRef startCell As Range)
 Dim currentBook As Workbook, currentSheet As Worksheet
 Set currentBook = ActiveWorkbook
 Set currentSheet = ActiveSheet
 Dim printBook As Workbook, printSheet As Worksheet
 Set printSheet = startCell.Worksheet
 Set printBook = printSheet.Parent
 
 printBook.Activate
 printSheet.Activate
 Print2dArrayToSheet printBook, printSheet, pReportData, startCell
 
 Dim LB1 As Long, UB1 As Long
 Dim LB2 As Long, UB2 As Long
 AssignArrayBounds pReportData, LB1, UB1, LB2, UB2
 
 Dim firstCol As Long, lastCol As Long
 Dim firstRow As Long, lastRow As Long
 firstCol = startCell.Column
 firstRow = startCell.row
 lastCol = firstCol + (UB2 - LB2)
 lastRow = firstRow + (UB1 - LB1)
 
 Set printRange = printSheet.Range(startCell, Cells(lastRow, lastCol))
 
 Dim col As Long
 Dim columnRange As Range
 Dim header As Variant
 Dim formatString As String
 For col = firstCol To lastCol
 With printSheet
 header = .Cells(firstRow, firstCol)
 If NumberFormatsOfHeaderColumns.Exists(header) Then
 Set columnRange = .Range(Cells(firstRow, col), Cells(lastRow, col))
 formatString = NumberFormatsOfHeaderColumns.item(header)
 columnRange.NumberFormat = formatString
 End If
 End With
 Next col
 
 currentBook.Activate
 currentSheet.Activate
 
End Sub

Auxilary Methods

'/============================================================================================================================================================
Public Sub SetDescriptionOfHeader(ByVal description As String, ByVal header As Variant)
 pMapDescriptionsToHeaders.item(description) = header
End Sub
Public Function GetHeaderFromDescription(ByVal description As String) As Variant
 If IsObject(pMapDescriptionsToHeaders.item(description)) Then
 Set GetHeaderFromDescription = pMapDescriptionsToHeaders.item(description)
 Else
 GetHeaderFromDescription = pMapDescriptionsToHeaders.item(description)
 End If
End Function
'/============================================================================================================================================================
Public Sub SetColumnIndexOfHeader(ByVal colIndex As Long, ByVal header As Variant)
 pColumnIndexesOfHeaders.item(header) = colIndex
End Sub
Public Function GetColumnIndexOfHeader(ByVal header As Variant)
 GetColumnFormattingOfHeader = pColumnIndexesOfHeaders.item(header)
End Function
'/============================================================================================================================================================
Public Sub SetColumnFormattingOfHeader(ByVal header As Variant, ByVal formatString As String)
 pColumnIndexesOfHeaders.item(header) = formatString
End Sub
Public Function GetColumnFormattingOfHeader(ByVal header As Variant) As String
 GetColumnFormattingOfHeader = pColumnIndexesOfHeaders.item(header)
End Function
'/============================================================================================================================================================
Public Function ColumnIndexesFromHeadersInArray(ByRef inputArray As Variant) As Scripting.Dictionary
 Dim dict As Scripting.Dictionary
 Set dict = New Scripting.Dictionary
 
 Dim ixHeaderRow As Long, LB2 As Long, UB2 As Long
 AssignArrayBounds inputArray, LB1:=ixHeaderRow, LB2:=LB2, UB2:=UB2
 
 Dim header As Variant, columnIndex As Long
 Dim iy As Long
 
 For iy = LB2 To UB2
 columnIndex = iy
 header = inputArray(ixHeaderRow, iy)
 dict.item(header) = columnIndex
 Next iy
 
 Set ColumnIndexesFromHeadersInArray = dict
End Function
'/============================================================================================================================================================
Public Function CreateDictOfUnidRowNumbers(ByRef inputArray As Variant, ByVal unidHeader As Variant) As Scripting.Dictionary
 Dim dict As Scripting.Dictionary
 Set dict = New Scripting.Dictionary
 
 Dim LB1 As Long, UB1 As Long
 AssignArrayBounds inputArray, LB1, UB1
 
 Dim ixUnidColumn As Long
 ixUnidColumn = pColumnIndexesOfHeaders.item(unidHeader)
 
 Dim unid As Variant, row As Long
 
 For row = LB1 To UB1
 unid = inputArray(row, ixUnidColumn)
 If dict.Exists(unid) Then
 '/ TODO: Error Handling
 Stop
 Else
 dict.item(unid) = row
 End If
 Next row
 
 Set CreateDictOfUnidRowNumbers = dict
End Function
'/============================================================================================================================================================
Public Sub ReplaceDataArray(ByRef inputArray As Variant)
 Erase pReportData
 pReportData = inputArray
 
 Set pColumnIndexesOfHeaders = ColumnIndexesFromHeadersInArray(pReportData)
End Sub
'/============================================================================================================================================================
Public Function GetFilteredReport(ByRef sourceReport As CLS_Data_Report, ByVal columnHeader As Variant, ByVal operator As ComparisonOperator, ByVal comparisonValue As Variant, ByVal keepOrRemoveOnTrue As KeepOrRemove) As CLS_Data_Report
 Dim filteredReport As CLS_Data_Report
 Set filteredReport = sourceReport.CloneProperties(sourceReport)
 
 Dim filterColumn As Long
 filterColumn = pColumnIndexesOfHeaders.item(columnHeader)
 
 Dim dataArray As Variant
 
 dataArray = filteredReport.reportData
 
 dataArray = KeepOrRemoveArrayRowsWhereComparisonIsTrue(dataArray, filterColumn, operator, comparisonValue, hasHeaders:=True, keepOrRemoveOnTrue:=keepOrRemoveOnTrue)
 
 filteredReport.ReplaceDataArray dataArray
 
 Set GetFilteredReport = filteredReport
End Function
'/==============================================================================
Public Function CloneProperties(ByRef sourceReport As CLS_Data_Report) As CLS_Data_Report
 Dim clonedReport As CLS_Data_Report
 Set clonedReport = New CLS_Data_Report
 
 Set clonedReport.printRange = sourceReport.printRange
 Set clonedReport.reportData = sourceReport.reportData
 Set clonedReport.MapDescriptionsToHeaders = sourceReport.MapDescriptionsToHeaders
 Set clonedReport.ColumnIndexesOfHeaders = sourceReport.ColumnIndexesOfHeaders
 Set clonedReport.NumberFormatsOfHeaderColumns = sourceReport.NumberFormatsOfHeaderColumns
 
 Set CloneProperties = clonedReport
End Function

Used Methods from my "Standard Methods" Module

Option Explicit
Public Enum ComparisonOperator
 NotEqualTo = 0
 LessThan = 1
 LessThanOrEqualTo = 2
 EqualTo = 3
 GreaterThanOrEqualTo = 4
 GreaterThan = 5
End Enum
Public Enum KeepOrRemove
 Remove = 0
 Keep = 1
End Enum
Public Function GetWorkbook(ByVal wbFilename As String, Optional ByVal wbFilePath As String) As Workbook
 Dim wbIsOpen As Boolean
 wbIsOpen = IsWorkbookOpen(wbFilename)
 
 If wbIsOpen Then
 Set GetWorkbook = Workbooks(wbFilename)
 Else
 If Len(wbFilePath) = 0 Then PrintErrorMessage "Workbook (" & wbFilename & ") is not open, and no filepath was supplied", stopExecution:=True
 Set GetWorkbook = Workbooks.Open(wbFilePath & wbFilename)
 End If
End Function
Public Function IsWorkbookOpen(ByVal wbFilename As String) As Boolean
'/ Credit to @Mat's Mug [http://codereview.stackexchange.com/users/23788/mats-mug] for suggesting improvements here [http://codereview.stackexchange.com/questions/114156/get-workbook-methods]
 
 On Error GoTo CleanFail:
 IsWorkbookOpen = Not Workbooks(wbFilename) Is Nothing
CleanExit:
 Exit Function
CleanFail:
 Err.Clear
 Resume CleanExit
End Function
Public Sub AssignArrayBounds(ByRef Arr As Variant, _
 Optional ByRef LB1 As Variant, Optional ByRef UB1 As Variant, _
 Optional ByRef LB2 As Variant, Optional ByRef UB2 As Variant, _
 Optional ByRef LB3 As Variant, Optional ByRef UB3 As Variant, _
 Optional ByRef LB4 As Variant, Optional ByRef UB4 As Variant, _
 Optional ByRef LB5 As Variant, Optional ByRef UB5 As Variant)
 
 If Not IsMissing(LB1) Then LB1 = LBound(Arr, 1)
 If Not IsMissing(UB1) Then UB1 = UBound(Arr, 1)
 
 If Not IsMissing(LB2) Then LB2 = LBound(Arr, 2)
 If Not IsMissing(UB2) Then UB2 = UBound(Arr, 2)
 
 If Not IsMissing(LB3) Then LB3 = LBound(Arr, 3)
 If Not IsMissing(UB3) Then UB3 = UBound(Arr, 3)
 
 If Not IsMissing(LB4) Then LB4 = LBound(Arr, 4)
 If Not IsMissing(UB4) Then UB4 = UBound(Arr, 4)
 
 If Not IsMissing(LB5) Then LB5 = LBound(Arr, 5)
 If Not IsMissing(UB5) Then UB5 = UBound(Arr, 5)
End Sub
Public Function Transpose2dArray(ByRef sourceArray As Variant) As Variant
 Dim LB1 As Long, UB1 As Long
 Dim LB2 As Long, UB2 As Long
 Dim i As Long, j As Long
 
 AssignArrayBounds sourceArray, LB1, UB1, LB2, UB2
 
 Dim transposedArray() As Variant
 ReDim transposedArray(LB2 To UB2, LB1 To UB1)
 
 For i = LB1 To UB1
 For j = LB2 To UB2
 transposedArray(j, i) = sourceArray(i, j)
 Next j
 Next i
 
 Transpose2dArray = transposedArray
 
End Function
Public Function RowFrom2dArray(ByRef sourceArray As Variant, ByVal rowIndex As Long) As Variant
 Dim LB2 As Long, UB2 As Long
 Dim i As Long
 
 Dim rowArray As Variant
 rowArray = Array()
 AssignArrayBounds sourceArray, LB2:=LB2, UB2:=UB2
 ReDim rowArray(LB2 To UB2)
 
 For i = LB2 To UB2
 rowArray(i) = sourceArray(rowIndex, i)
 Next i
 
 RowFrom2dArray = rowArray
 
End Function
Public Function IndexIn1dArray(ByRef sourceArray As Variant, ByVal searchItem As Variant, Optional ByVal nthMatch As Long = 1) As Variant
 Dim ix As Long, i As Long
 Dim matchesFound As Boolean, matchCounter As Long
 
 Dim LB1 As Long, UB1 As Long
 AssignArrayBounds sourceArray, LB1, UB1
 
 matchCounter = 0
 i = LB1
 Do Until matchCounter = nthMatch Or i > UB1
 If sourceArray(i) = searchItem Then
 matchCounter = matchCounter + 1
 ix = i
 End If
 i = i + 1
 Loop
 
 matchesFound = (matchCounter = nthMatch)
 If matchesFound Then
 IndexIn1dArray = ix
 Else
 IndexIn1dArray = CVErr(xlErrValue)
 End If
 
End Function
Public Sub CloseWorkbook(ByRef wbTarget As Workbook)
 Application.DisplayAlerts = False
 wbTarget.Close
 Application.DisplayAlerts = True
End Sub
Public Function Remove2DArrayRows(ByRef sourceArray As Variant, ByRef rowListArray As Variant) As Variant
 Dim targetArray As Variant
 targetArray = Array()
 
 Dim LB1 As Long, UB1 As Long
 Dim LB2 As Long, UB2 As Long
 AssignArrayBounds sourceArray, LB1, UB1, LB2, UB2
 ReDim targetArray(LB2 To UB2, LB1 To LB1)
 
 rowListArray = SortArrayList(rowListArray, sortAscending:=True)
 
 Dim row As Long, col As Long
 Dim copyCounter As Long, ixListArray As Long
 copyCounter = 0
 ixListArray = LBound(rowListArray)
 
 For row = LB1 To UB1
 If row = rowListArray(ixListArray) Then
 ixListArray = ixListArray + 1
 If ixListArray > UBound(rowListArray) Then ixListArray = UBound(rowListArray)
 Else
 ReDim Preserve targetArray(LB2 To UB2, LB1 To LB1 + copyCounter)
 For col = LB2 To UB2
 targetArray(col, LB1 + copyCounter) = sourceArray(row, col)
 Next col
 
 copyCounter = copyCounter + 1
 End If
 Next row
 
 targetArray = Transpose2dArray(targetArray)
 Remove2DArrayRows = targetArray
 
End Function
Public Function KeepOrRemoveArrayRowsWhereComparisonIsTrue(ByRef sourceArray As Variant, ByVal colIndex As Long, ByVal operator As ComparisonOperator, ByVal comparisonValue As Variant, ByVal hasHeaders As Boolean, ByVal keepOrRemoveOnTrue As KeepOrRemove) As Variant
 Dim LB1 As Long, UB1 As Long
 AssignArrayBounds sourceArray, LB1, UB1
 
 Dim rowsToBeRemoved As Variant, removeCounter As Long
 rowsToBeRemoved = Array()
 ReDim rowsToBeRemoved(1 To 1)
 
 Dim ix As Long, startRow As Long
 If hasHeaders Then startRow = LB1 + 1 Else startRow = LB1
 
 Dim sourceValue As Variant
 
 Select Case keepOrRemoveOnTrue
 
 Case Is = KeepOrRemove.Keep
 removeCounter = 0
 For ix = startRow To UB1
 sourceValue = sourceArray(ix, colIndex)
 If Not ComparisonIsTrue(sourceValue, operator, comparisonValue) Then
 removeCounter = removeCounter + 1
 ReDim Preserve rowsToBeRemoved(1 To removeCounter)
 rowsToBeRemoved(removeCounter) = ix
 End If
 Next ix
 
 Case Is = KeepOrRemove.Remove
 removeCounter = 0
 For ix = startRow To UB1
 sourceValue = sourceArray(ix, colIndex)
 If ComparisonIsTrue(sourceValue, operator, comparisonValue) Then
 removeCounter = removeCounter + 1
 ReDim Preserve rowsToBeRemoved(1 To removeCounter)
 rowsToBeRemoved(removeCounter) = ix
 End If
 Next ix
 
 End Select
 
 sourceArray = Remove2DArrayRows(sourceArray, rowsToBeRemoved)
 
 KeepOrRemoveArrayRowsWhereComparisonIsTrue = sourceArray
End Function
Public Function ComparisonIsTrue(ByVal sourceValue As Variant, ByVal operator As ComparisonOperator, ByVal comparisonValue As Variant) As Boolean
 Dim isTrue As Boolean
 
 Select Case operator
 
 Case ComparisonOperator.NotEqualTo
 isTrue = (sourceValue <> comparisonValue)
 
 Case ComparisonOperator.LessThan
 isTrue = (sourceValue < comparisonValue)
 
 Case ComparisonOperator.LessThanOrEqualTo
 isTrue = (sourceValue <= comparisonValue)
 
 Case ComparisonOperator.EqualTo
 isTrue = (sourceValue = comparisonValue)
 
 Case ComparisonOperator.GreaterThanOrEqualTo
 isTrue = (sourceValue >= comparisonValue)
 
 Case ComparisonOperator.GreaterThan
 isTrue = (sourceValue > comparisonValue)
 
 Case Else
 '/ Error Handling
 Stop
 
 End Select
 
 ComparisonIsTrue = isTrue
End Function
Public Function ArrayIsAllocated(inputArray As Variant) As Boolean
 On Error Resume Next
 ArrayIsAllocated = IsArray(inputArray) And Not IsError(LBound(inputArray, 1)) And LBound(inputArray, 1) <= UBound(inputArray, 1)
 On Error GoTo 0
 
End Function
asked Feb 1, 2016 at 13:06
\$\endgroup\$

2 Answers 2

5
\$\begingroup\$

Just a quick shot at

Public Property Get MapDescriptionsToHeaders() As Scripting.Dictionary
 Set MapDescriptionsToHeaders = pMapDescriptionsToHeaders
End Property
Public Property Set MapDescriptionsToHeaders(ByRef descriptions As Scripting.Dictionary)
 Set pMapDescriptionsToHeaders = MapDescriptionsToHeaders
End Property 

you aren't assigning the descriptions As Scripting.Dictionary but you are calling the getter out of the setter which seems to be some copy&pasta bug.

answered Feb 1, 2016 at 13:17
\$\endgroup\$
3
  • \$\begingroup\$ Be aware, you have some more of these. \$\endgroup\$ Commented Feb 1, 2016 at 13:34
  • \$\begingroup\$ Damnit. I could've sworn I fixed those. \$\endgroup\$ Commented Feb 1, 2016 at 13:40
  • 1
    \$\begingroup\$ A sane language wouldn't allow a Getter to not return anything. ++ \$\endgroup\$ Commented Feb 2, 2016 at 10:06
2
\$\begingroup\$

This only works by sheer luck.

Public Sub AddDataToReport(ByRef inputArray As Variant, ByVal mergeArrays As Boolean, Optional ByVal unidHeader As Variant, Optional ByVal overrideValues As Boolean)
 If mergeArrays Then
 If IsMissing(unidHeader) Or IsMissing(overrideValues) Then 

I made the same mistake once upon a time. The problem is that the IsMissing() function only works for Variant types. Asking if a simple value type is missing just doesn't make sense, because they have default values.

This MVCE should highlight what I'm talking about.

Private Sub TestIsMissing(Optional bool As Boolean)
If IsMissing(bool) Then
 MsgBox "Was Missing!"
Else
 MsgBox bool
End If
End Sub
Private Sub test()
 TestIsMissing True
 TestIsMissing False
 TestIsMissing
End Sub

In short, the second half of this expression will always return False.

If IsMissing(unidHeader) Or IsMissing(overrideValues) Then

So, I believe you could remove the second half, but it's possible that it's actually a bug and you need to think harder about what it is that you're trying to check.

answered Feb 2, 2016 at 10:23
\$\endgroup\$
3
  • 1
    \$\begingroup\$ You're right, I knew about IsMissing() only applying to variants but must've forgotten it for the second argument. I guess this is why I should write Unit Tests ^^ \$\endgroup\$ Commented Feb 2, 2016 at 11:41
  • \$\begingroup\$ You know, there's a tool for that. =;)- \$\endgroup\$ Commented Feb 2, 2016 at 12:33
  • \$\begingroup\$ I know, but the code inspections bury me in 500 lines of "multiple declarations on one line" so it's easy to miss stuff (and yes, I've told it to ignore thiose, but to no avail) \$\endgroup\$ Commented Feb 2, 2016 at 14:44

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.