About
- This question is not about when to use a
Function
or aSub
, or the difference betweenByRef
andByVal
(although some insights will be unavoidable). - It is about scenarios which are 'commonly' solved with a
Function
, but can optionally be solved with aSub
usingByRef
in the sense of 'modifying'.
The Code
Consider the following function:
' Returns the worksheet (object) with a specified name in a specified workbook (object).
Function getWsF(wb As Workbook, _
ByVal wsName As String) _
As Worksheet
' 'getWsF' is 'Nothing' by default.
' Try to define worksheet.
On Error Resume Next
Set getWsF = wb.Worksheets(wsName)
End Function
You can utilize it like the following:
' Writes the name of a specified worksheet, if it exists, to the `Immediate` window...
Sub testFunction()
Const wsName As String = "Sheet1"
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define worksheet.
Dim ws As Worksheet
Set ws = getWsF(wb, wsName)
' Test if worksheet exists.
If Not ws Is Nothing Then
Debug.Print "The worksheet name is '" & ws.Name & "'."
Else
Debug.Print "Worksheet '" & wsName & "' doesn't exist in workbook '" _
& wb.Name & "'."
End If
End Sub
But you can also write each of the procedures in the following way:
' Although 'ByRef' is not necessary, I'm using it to indicate that whatever
' its variable is referring to in another procedure (in this case
' a worksheet object), is going to be modified (possibly written to
' for other datatypes).
Sub getWsS(ByRef Sheet As Worksheet, _
wb As Workbook, _
ByVal wsName As String)
' 'Sheet' could be 'Nothing' or an existing worksheet. You could omit
' the following line if you plan to use the procedure immediately
' after declaring the worksheet object, but I would consider it
' as too risky. Therefore:
' 'Reinitialize' worksheet variable.
Set Sheet = Nothing
' Try to define worksheet.
On Error Resume Next
Set Sheet = wb.Worksheets(wsName)
End Sub
' Writes the name of a specified worksheet, if it exists, to the `Immediate` window...
Sub testSub()
Const wsName As String = "Sheet1"
Dim wb As Workbook
Set wb = ThisWorkbook ' The workbook containing this code.
' Define worksheet.
Dim ws As Worksheet
getWsS ws, wb, wsName
' Test if worksheet exists.
If Not ws Is Nothing Then
Debug.Print "The worksheet name is '" & ws.Name & "'."
Else
Debug.Print "Worksheet '" & wsName & "' doesn't exist in workbook '" _
& wb.Name & "'."
End If
End Sub
Side by Side
Procedure
Function getWsF(wb As Workbook, _ Sub getWsS(ByRef Sheet As Worksheet, _
wsName As String) _ wb As Workbook, _
As Worksheet wsName As String)
Set Sheet = Nothing
On Error Resume Next On Error Resume Next
Set getWsF = wb.Worksheets(wsName) Set Sheet = wb.Worksheets(wsName)
End Function End Sub
Usage (relevant)
' Define worksheet. ' Define worksheet.
Dim ws As Worksheet Dim ws As Worksheet
Set ws = getWsF(wb, wsName) getWsS ws, wb, wsName
The Question(s)
- Is the second solution viable?
- I'm looking for a proper description of what each of the relevant two procedures do and some insights in terms of common practice, readability, efficiency, pitfalls ...