In terms of performance, this would not be any significant issue here.

The main difference is that user defined function can be used in expression in your code, where as a sub cannot.

This is really a HUGE Mount Everest of a difference here.

This difference is not really limited to Access, but tends to applies to every programing language and system I can think of that supports the creating of user defined functions.

The key advantage of using defined function are MANY but the most basic issue is that such function can be used in EXPRESSIONS.

For example, in an on click setting for a button on a form, you can generally have a single VBA [Event Code] routine attached to that button.

However you can ALSO place an expression in the property sheet like this:

=MyUserFunction()

The above is a handy tip, since then you can highlight 10 controls on a form, and type in the above expression and you just assigned the above function to those 10 buttons. You cannot do the above with a sub.

Another significant difference is you can use a function as a data source (expression) for a text box on a form or report (again you cannot do this with a sub).

Another significant difference is you can utilize these functions in SQL. This is a truly fantastic ability as then you can have code "run" for each row of a query. And this means you can extend the ability and functionally of SQL.

And you can even use this idea to display a VBA variable in a sql query as you simply build a public function that returns the VBA variable and this can be used in a query – you cannot however use VBA variables in a query!

And this extending of SQL opens up endless ideas:

So I can build a public function called ToMorrow()

Public Function Tomorrow() as date

   Tomorrow() = date() + 1

End Function.

Now in the query builder, I can go:

Select FirstName, lastName, Tomorrow() as NextDay from tblCustomers

And you can even make custom conversions such as:

Select FirstName, LastName, Celsius([DailyGreenHouseTemp]) from tblGreenHouse.

The above Daily temperature reading could in in Fahrenheit and you simply have to define a public function called Celsius like this:

Public Function Celsius(Temperature As Variant) As Variant

   Celsius = (Temperature * 1.8) + 32

End Function

Now while the above function is simple, it could do complex record set processing a complex algorithm to determine the moisture above a flower pot based on temperature and humidity.

So once we define such a public function, then the key concept is such a function can be used not only in VBA code as an expression, but ALSO can be used amazing enough this ability includes SQL.

So even in code, you can go:

If MyCustomfucntion(SomeVar) = lngTestValue then

Again in the above, you cannot use a sub in VBA expressions.

And even more interesting is when using custom XML for ribbons in Access, then if you use a function() expression for the "on action" attribute then you can avoid the need for ribbon call backs. Even better is the ribbon will call those functions() in the current form, not a public code module like you MUST do with ribbon call backs.

I could probably type on for another 10+ pages as to the difference, but I think that would start to be redundant and I don't want to appear condensing in any way here.

So the basic difference between a sub and function in VBA or in fact in most programming languages is quite much the same.

And the benefits of using a function in Access or just about any programing language are also much the same. For example I can define a user defined function in t-sql (scalar) – and again you then are free to use that t-sql function in any of your t-sql code or even quires that you create and use for sql server.

So this is basic and simple difference between a sub and a function, and I dare say those who have written computer code will in just about any programing language will instantly realize the above significant and useful differences between a subroutine and a function.

Answer from Albert D. Kallal on Stack Overflow
🌐
Microsoft Learn
learn.microsoft.com › en-us › office › vba › language › reference › user-interface-help › function-statement
Function statement (VBA) | Microsoft Learn
' If a function's arguments are defined as follows: Function MyFunc(MyStr As String,Optional MyArg1 As _ Integer = 5,Optional MyArg2 = "Dolly") Dim RetVal ' The function can be invoked as follows: RetVal = MyFunc("Hello", 2, "World") ' All 3 arguments supplied. RetVal = MyFunc("Test", , 5) ' Second argument omitted. ' Arguments one and three using named-arguments. RetVal = MyFunc(MyStr:="Hello ", MyArg1:=7) ... Have questions or feedback about Office VBA or this documentation?
🌐
GoSkills
goskills.com › microsoft excel › resources
How To Write VBA Functions | GoSkills
December 18, 2023 - There isn’t a built-in function in Excel that is able to do that, but a user-defined function could be written and used in Excel. Download your free practice file! ... Let’s go through an Excel VBA function example of how to write a function that would calculate the sales commission for a salesperson based on the number of sales made.
Discussions

vba - Purpose of using sub routines over functions - Stack Overflow
I've been working with Access for a while now, and although I understand the obvious benefit of a Function over a Sub, been that it can return values as a result, I'm not sure as to why I should us... More on stackoverflow.com
🌐 stackoverflow.com
excel - Function execution with parameters in VBA - Stack Overflow
I'm creating a function that has as a parameter a day of the week (Monday, Wednesday, Thursday ...) that captures the day of the respective month of the week and returns its day in the cell, on Sun... More on stackoverflow.com
🌐 stackoverflow.com
VBA Essentials: User-defined functions
Excellent presentation. Very helpful. One correction: In your "ADDFIVE() revised" section, the parameter must be a Variant, rather than a Long (because you allow for the parameter to be a number or some other type). A couple of suggestions, based on common errors that I've encountered when reviewing spreadsheets: It would be useful to add a brief section about Volatile functions. VBA functions used in a worksheet aren't recalculated automatically by default, leading to out-of-date results. See https://docs.microsoft.com/en-us/office/vba/api/excel.application.volatile It is a good practice to assign to the function name only once, just before exiting the function. For all other assignments, use a temporary variable. The reason for doing this is that if you change the function's name, then the assignment needs to be changed in only one place. Often I've seen a function whose name has changed, but not all assignments within the function have been changed, so the logic in wrong. For example, to modify one of your examples: Function ADDFIVE(val As Variant) As String Dim Result as String If IsNumeric(val) Then Result = cStr(val + 5) Else Result = "Error: val Parameter Is Not numeric" End If ADDFIVE = Result End Function More on reddit.com
🌐 r/excel
25
202
January 12, 2019
Call a VBA Function into a Sub Procedure - Stack Overflow
I know this is a simple question for someone out there, but I have never really used function module at all because I did not understand what they were. So I have a whole bunch of things I can use... More on stackoverflow.com
🌐 stackoverflow.com
🌐
Excel Easy
excel-easy.com › vba › function-sub.html
Function and Sub in Excel VBA (Easy Steps)
Explanation: The function returns a value so you have to 'catch' this value in your code. You can use another variable (z) for this. Next, you can add another value to this variable (if you want). Finally, display the value using a MsgBox. Result when you click the command button on the sheet: If you want Excel VBA to perform some actions, you can use a sub.
🌐
Microsoft Learn
learn.microsoft.com › en-us › office › vba › language › concepts › getting-started › writing-a-function-procedure
Writing a Function procedure (VBA) | Microsoft Learn
September 13, 2021 - Sub Main() temp = Application.InputBox(Prompt:= _ "Please enter the temperature in degrees F.", Type:=1) MsgBox "The temperature is " & Celsius(temp) & " degrees C." End Sub Function Celsius(fDegrees) Celsius = (fDegrees - 32) * 5 / 9 End Function ... Have questions or feedback about Office VBA or this documentation?
🌐
Wikihow
wikihow.com › computers and electronics › software › programming › how to call a function in microsoft visual basic
Calling Functions in VB & VBA: Syntax, Examples, & More
February 19, 2026 - Use the syntax lvalue = functionName (argument1, argument2) to call functions in VB and VBA. If there are no arguments, omit the parentheses or leave them blank.
Top answer
1 of 7
20

In terms of performance, this would not be any significant issue here.

The main difference is that user defined function can be used in expression in your code, where as a sub cannot.

This is really a HUGE Mount Everest of a difference here.

This difference is not really limited to Access, but tends to applies to every programing language and system I can think of that supports the creating of user defined functions.

The key advantage of using defined function are MANY but the most basic issue is that such function can be used in EXPRESSIONS.

For example, in an on click setting for a button on a form, you can generally have a single VBA [Event Code] routine attached to that button.

However you can ALSO place an expression in the property sheet like this:

=MyUserFunction()

The above is a handy tip, since then you can highlight 10 controls on a form, and type in the above expression and you just assigned the above function to those 10 buttons. You cannot do the above with a sub.

Another significant difference is you can use a function as a data source (expression) for a text box on a form or report (again you cannot do this with a sub).

Another significant difference is you can utilize these functions in SQL. This is a truly fantastic ability as then you can have code "run" for each row of a query. And this means you can extend the ability and functionally of SQL.

And you can even use this idea to display a VBA variable in a sql query as you simply build a public function that returns the VBA variable and this can be used in a query – you cannot however use VBA variables in a query!

And this extending of SQL opens up endless ideas:

So I can build a public function called ToMorrow()

Public Function Tomorrow() as date

   Tomorrow() = date() + 1

End Function.

Now in the query builder, I can go:

Select FirstName, lastName, Tomorrow() as NextDay from tblCustomers

And you can even make custom conversions such as:

Select FirstName, LastName, Celsius([DailyGreenHouseTemp]) from tblGreenHouse.

The above Daily temperature reading could in in Fahrenheit and you simply have to define a public function called Celsius like this:

Public Function Celsius(Temperature As Variant) As Variant

   Celsius = (Temperature * 1.8) + 32

End Function

Now while the above function is simple, it could do complex record set processing a complex algorithm to determine the moisture above a flower pot based on temperature and humidity.

So once we define such a public function, then the key concept is such a function can be used not only in VBA code as an expression, but ALSO can be used amazing enough this ability includes SQL.

So even in code, you can go:

If MyCustomfucntion(SomeVar) = lngTestValue then

Again in the above, you cannot use a sub in VBA expressions.

And even more interesting is when using custom XML for ribbons in Access, then if you use a function() expression for the "on action" attribute then you can avoid the need for ribbon call backs. Even better is the ribbon will call those functions() in the current form, not a public code module like you MUST do with ribbon call backs.

I could probably type on for another 10+ pages as to the difference, but I think that would start to be redundant and I don't want to appear condensing in any way here.

So the basic difference between a sub and function in VBA or in fact in most programming languages is quite much the same.

And the benefits of using a function in Access or just about any programing language are also much the same. For example I can define a user defined function in t-sql (scalar) – and again you then are free to use that t-sql function in any of your t-sql code or even quires that you create and use for sql server.

So this is basic and simple difference between a sub and a function, and I dare say those who have written computer code will in just about any programing language will instantly realize the above significant and useful differences between a subroutine and a function.

2 of 7
13

The main difference is not only the return value, it seems that subs are faster than functions (at least in .net) because the MSIL code of subs is much shorter when no value is returned. so overall subs are faster when no value is returned. oh i've just found a great source for it (talks about .net), maybe you would like to read further about it- Functions vs. Subroutines

Find elsewhere
Top answer
1 of 2
6

Functions should take an input, compute a result, and then return that result; the return type of your function is implicitly Variant, and its return value is never assigned, so callers can only ever receive a Variant/Empty value out of it.

[...] and returns its day in the cell

Ok, I see the idea now - simple misunderstanding. If what you want is ultimately a UDF (user-defined function) that is invoked from a formula in a cell:

Copy=DayReference(D3)

There are a number of rules for this to work.

  • First rule is that functions cannot have side effects: running it should not affect any cells, sheets, Application state, or anything in global scope.

  • Second rule is that functions should normally take all their dependencies as parameters, such that invoking it with the same parameters reliably yields the same output. For example if a function needs a Date value, it should take that date as a parameter instead of just working with whatever the current date is. That way you can test and prove that the function returns the expected output given a Sunday.

    CopyPublic Function DayReference(ByVal wkDay as Long, ByVal refDate As Date) As Variant
    
        If Weekday(refDate, vbSunday) = wkDay Then
            DayReference = Day(refDate)
        ElseIf Weekday(Date, 1) = vbSunday Then
            DayReference = ""
        End If        
    
    End Function
    

The function returns a Variant/Long (the day of the refDate) when the WeekDay of the specified refDate is the specified wkDay value, and a Variant/String (and empty string) when that weekday is vbSunday.

You could invoke it like this in a cell:

Copy =DayReference(A1,TODAY())

Or like this in VBA code:

CopyDim d As Variant
d = DayReference(Sheet1.Range("A1").Value, Date)
Debug.Print d

Or from the immediate pane (Ctrl+G):

Copy?DayReference(vbSaturday, DateSerial(2020, 8, 22))
 22
2 of 2
0

Try it in this way, please:

CopyFunction dayReference(week As Integer)
    If Weekday(Date, 1) = week Then
        dayReference = Day(Date)
    ElseIf Weekday(Date, 1) = 1 Then
        dayReference = ""
    End If
End Function

The function must be copied in a standard module.

It can be called from a cell, in this way:

Copy=dayReference(7)

It will return 0 if none of the two conditions is True.

Edited:

If you want calling it, not from a cell, you can do it in this way:

CopySub testdayReference()
  Debug.Print dayReference(7)
  'or
  ActiveCell.Value = dayReference(1)
End Sub
🌐
Better Solutions
bettersolutions.com › vba › macros › functions.htm
VBA Macros - Functions - Functions
4 weeks ago - Functions always return a single value. In order to return a value from a function we must assign the function's name to a return value. A function is identical to a subroutine but also has the ability to return a value.
🌐
Reddit
reddit.com › r/excel › vba essentials: user-defined functions
r/excel on Reddit: VBA Essentials: User-defined functions
January 12, 2019 -

Hi All. In this post I’m going to be describing how to create function procedures to create your own functions in VBA.

Note 1: This is an intermediate level VBA post. I assume that you know how to use variables, arrays and loops in this post. If you do not, it would probably help to read the writeup guides we have on the subject. You can see those guides here in the VBA section.

Note 2: The terms "parameter" and "argument" are not the same and refer to different things. This post uses those terms interchangeably, which is fairly common.

Functions are one of two types of procedures in VBA: the other are subroutines, which are occasionally called macros. There are two types of functions: Worksheet functions and VBA functions. I will be discussing both in this post.

If you have even some of the most basic knowledge of Excel, you’ve used functions before: They’re what you use in your formulas. Functions typically take a number of parameters (although some take none) and return a value. So a user-defined worksheet function is a function that you can call from the worksheet (or VBE) in the same way that you do with native Excel worksheet functions.

Excel has so many functions available to you. You may wonder what the point would be to create your own functions. There are several reasons for creating your own functions:

  1. You have complicated formulas that, perhaps invoke several different formulas and parameters. You can simplify this by putting all of the logic in your own user-defined function.

  2. Once you create a function, you can make use of it in multiple cells, worksheets, workbooks, etc. Just like you can with native worksheet functions (if they’re in an addin)

  3. You want to get the result of a value on the worksheet, perhaps once or several times, without deleting your undo stack

  4. You want to assign a value to a variable or array in VBA that is processed in some way.

Now that we have an introductions to functions and why you’d want to create your own, let’s look at function scope.

Public and private functions

Just like subroutines (macros), functions are public by default. For functions, this means that they’re available for use within the Excel worksheet, and within other modules in VBA. You can make the function private by using the private keyword before the function keyword like so:

Private Function ADDSFIVE()
‘code goes here
End Function

A private function is only available for use within the same module where it’s defined and is not displayed by the worksheet intellisense.

Differences between function and subroutines

There are a number of differences between subroutines and functions. Let’s take a look at some of them below:

  1. Only function procedures can return values. Note the use of my word can here. Function procedures are not required to return values. In Excel, if I call a function with no return value, it just returns the default value of whatever its return type is (e.g. false for bool, 0 for long, etc.)

  2. You can call function procedures to return values without deleting your undostack in the worksheet. This can’t be done with macros.

  3. Functions need to be defined in the current workbook or an addin to be called from the worksheet / VBE. They cannot be used if defined in your personal macro workbook. You can also qualify the workbook name with the function name to call them. (One thing you can do however, is define them in a module in your personal macro workbook, and then just drag that module into the VBProject in the workbook you want those functions in.)

  4. Any code which makes any modification to Excel is disabled in a function when called from a worksheet cell. Such code works when called from VBE.

  5. Typically, macros crash and break on the line where a runtime error occurred. This does not happen in functions and can make them harder to debug.

  6. When you provide arguments to a subroutine, they are passed by reference by default. This means that VBA modifies the value of the original variable that was provided to the subroutine. In functions, they are passed by value. This means that a copy of the function uses a copy of the original value. You cannot pass a value in a function by reference with the exception of arrays, which must be passed by reference. However, you can work around this easily by assigning a variable to the value that’s returned by the processed function of itself. You can see an example of that below:

dim A as long
A = processFunction(A)

Note: this does not work with arrays

So now we have some background with functions, let’s start with some examples:

First function example: ADDFIVE()

Option Explicit
Function ADDFIVE(val As Long)
ADDFIVE= val + 5
End Function

In this example, a function is created which accepts one parameter. In the function, there is just one line of code. The single line of code is an expression. If you notice, the name that we’re assigning the value of val + 5, ADDSFIVE, has the same name as the name of the function. In the body of this function, ADDFIVE is essentially just a special type of variable. Since the ADDFIVE variable has the same name as the function, it is the value that’s ultimately returned by the function.

So if you use this function in the Excel worksheet, the ADDFIVE function would return the value of the val parameter + 5, because that’s the value we assigned to the function.

One thing you may notice is that option explicit is enabled, but there’s no dim statement in the function to declare the variable ‘val’. The dim statement is not required for variables declared in the parentheses next to the function name. It is however required for all variables declared between the function and end function statements.

Another thing you may notice is that, like native Excel worksheet functions, ADDFIVE is in all capitals. You can name your functions in lowercase, capitals, or use mixed case.

One thing we may wonder about ADDFIVE is, what if we assign the value to val to be something that’s not numeric, like a string? Let’s take a look at an example in the next section.

ADDFIVE() revised

=ADDFIVE(“Hello World!!”)

The error Excel gives me is a #VALUE! Error when I use this formula in the worksheet. As I said before, functions do not break on the line where the error occurred. So, if you’re function was relatively long, it can be difficult to find where the error is.

One thing we can do is check for the value type supplied and run different code depending on what is supplied. Let’s take a look at the ADDFIVE function with additional logic to check user input:

Function ADDFIVE(val As variant)
    dim temp as variant
    If IsNumeric(val) Then
            temp = val + 5
    Else
        temp = “Error: val Parameter Is Not numeric”
    End If
    ADDFIVE = temp
End Function

This function is a bit more complicated than the first function, so let’s start breaking it down. The first thing that's done is declare a temp variable of the variant data type (variant is used because we can return a number type or string type.) Unlike our first function, which just returned an expression, this function does some type checking. The first thing this function does is check if the val variable is numeric. If it isn’t, then the temp variable is assigned the error message and returned by the function. If it is, then the temp variable is assigned the expression val + five and the function returns this value.

It can be helpful to use a temp variable like this in case you ever need to rename a function. If so, you only need to replace the function name in one place, which will be at the end of the procedure.

Once you have this function entered in a module in VBA, you can call this function like a regular Excel function in the worksheet. You can also call this function in VBA. With ADDSFIVE defined in a module, you can run the following code in the immediate window:

debug.print ADDFIVE(5) ‘returns 10

Now that we have an idea of how functions work, let’s take a look at return types.

Function return types

By default, if you don’t declare datatypes for variables, they can be set to any type. Similarly, for functions, if you don’t declare a return type, they can return any type. Because of this, it’s recommended that you explicitly return the datatypes for your functions. This can be done like so:

Function ADDFIVE(val As Long) As String
‘code goes here
End Function

The ‘as string’ declaration sets the return type of the function to a string. So whether add five returns the sum of two numbers, or an error, it will return a string either way.

One thing that’s important to note about function return types is that they do not require the function to return values. So you can write code like so:

Function ADDSFIVE() As String
‘no code in this function
End Function

Now, what happens if we run this function? Will it return an error? Unfortunately, no error is returned. There is no error because functions do not require return types. So what does the function return? Well, as I said earlier, what the function returns depends on depends on the datatype the function is set to return. Since we’re saying the function return type will be a string, if no value is returned, the value will be set to an uninitialized string which is “”.

Because of this, you should always have option explicit turned on when you write function procedures. A simple typo can change your function from having a return value to having no return value at all. And if you don’t have option explicit turned on, VBE will not warn you of this mistake.

Nesting functions

Just like you can with Excel worksheet functions, you can also nest function procedures you from your own user-defined functions. In VBA, this is done by passing one function as the parameter to another function. You can see an example below

Function HW()

HW = "Hello world"

End Function

Function EXCLAM(val As String)

EXCLAM = val & "!!"

End Function

‘in immediate window
Debug.print debug.Print EXCLAM(HW())
‘prints Hello world!!

Exit function statement

One thing that’s important to note about functions is that, even if you return a value, this does not necessarily exit a function. You may, for example, be in a loop, and the loop may continue processing even after you assign the value of a function. To deal with this, we have the exit function statement which allows us to exit at a point of our choosing. Let’s take a look at such a function in an example below:

Function INRANGE(val As String, rang As Range) As Boolean
Dim cell As Range
For Each cell In rang
    If val = cell.Value Then
        INRANGE = True
        Exit Function
    End If
Next cell
INRANGE = False
End Function

The INRANGE() function accepts two parameters: a val parameter and a range parameter. And the INRANGE function will ultimately return a Boolean value. A variable named cell is declared of the range datatype. Using this variable, a for-each-next loop is done that compares the value of the cells in the range to val. If any of the cells have a value that matches val, INRANGE is set to true, and the function exits. Since the value of INRANGE is set to true if the function exits using the exit function statement, true is returned by the function. If no such match is found, and the loop exits, INRANGE is set to a value of false before it exits the function in a natural way. And since false is the value its set to before the function exits, that’s the value that’s returned by the function.

Functions that have optional parameters

When you write functions, sometimes you want to provide optional parameters that can be utilized as necessary when the function is called. Optional parameters are specified with the optional keyword. Their data type must be variant. And they must be provided after all mandatory parameters. When you use optional parameters, you have to check whether they’re provided with this ismissing function as you can see below as you can see below:

Function BILINGUALGREET(lang As String, Optional name As Variant)

Dim greet As String

If lang = "E" Then
    greet = "Hello"
ElseIf lang = "S" Then
    greet = "Hola"
End If

If IsMissing(name) Then
    greet = greet & "!"
Else
    greet = greet & " " & name & "!"
End If

BILINGUALGREET = greet

End Function

This function, BILINGUALGREET specifies a greeting either in English or Spanish. The optional parameter “name”, of the variant type, comes after the mandatory parameter “lang”. If “name” is provided an argument, that name is also included in the greeting.

Functions that can take varying parameters

All of the examples so far have looked at functions that have a fixed amount of parameters. With certain functions, you don’t know how many arguments will be provided until it’s called. Sometimes you may want a function that takes one parameter, sometimes three, sometimes six, etc. If you had a function with a fixed amount of parameters, the function would fail when provided with too few or too many arguments. In VBA, you can create functions that can take dynamic parameters. You can create a function that takes a dynamic number of parameters using the paramarray keyword, which you can see used in the example below:

Function SUMMY(ParamArray args() As Variant)

Dim temp As Long, i As Long

temp = 0

For i = LBound(args) To UBound(args)
    If IsNumeric(args(i)) Then
        temp = temp + args(i)
    End If
Next i

SUMMY = temp

End Function

The paramarray keyword is specified before the array named args, which is a dynamic array. Once the dynamic array is provided, the array is iterated with using a for loop. A conditional statement then checks whether the current element of the array is numeric. And if it is, it is added to the temp variable. One the loop finishes, the temp variable is assigned to the function name. And this returns the value from the function.

Volatile functions

A volatile function is a function that recalculates automatically whenever any change is made is the workbook. This also includes stepping into a cell, even if you don’t make any changes. A few examples of functions that work this way are RAND(), RANDBETWEEN(), and NOW(). You can create your volatile functions by using the volatile property of the application object as you can see below:

Function DYNAMICRAND(Optional vol As Variant)
    
Dim temp As Double

Application.volatile

If Not IsMissing(vol) Then
    If vol = False Then
        Application.volatile False
    End If
End If

temp = Rnd

DYNAMICRAND = temp

End Function

This function works similarly to the RAND() function in Excel. It is a volatile function and recalculates any time any change is made in the workbook. The main difference is that it accepts an optional boolean parameter which allows you to turn volatility off. So if you pass in FALSE argument to the DYNAMICRAND() function, it will not be volatile

One thing that’s important to note is that, if you make use of a volatile function in your own code (e.g. worksheetfunction.randbetween()), this can make your function volatile. Once your function is volatile, it can not be made non-volatile by passing false parameter to application.volatile.

Array functions

All of the examples we’ve used so far only return a single value. However, functions can also return an array. You can take a look at an example below:

Function ADDFIVEARR(ByRef arr() As Long) As Variant
Dim i As Long

For i = LBound(arr) To UBound(arr)
    If IsNumeric(arr(i)) Then
        arr(i) = arr(i) + 5
    End If
Next i

ADDFIVEARR = arr

End Function

Sub subby()

Dim numsArr(2) As Long, funcArr() As Long, i As Long

numsArr(0) = 1
numsArr(1) = 2
numsArr(2) = 3

funcArr = ADDFIVEARR(numsArr)

For i = LBound(funcArr) To UBound(funcArr)
    Debug.Print numsArr(i)
Next i

'debug.print 6, 7, 8

End Sub

The function ADDSFIVEARR takes an array parameter. It goes through each element in the array. If the element is numeric, five is added to the value of that array element. And once all of the elements in the array have been iterated, the array is returned from the function. In this example, the array is called from the subroutine Subby that provides the argument for the function. There are a few things to note about this function:

  1. Once an array’s elements have been given values (like numsArr’s have) you can’t reassign those values to the array without clearing them. So, we use the dynamic array funcArr to get past this.

  2. The arr() parameter in ADDFIVEARR is passed byref explicitly. As I noted earlier, if arrays are passed as arguments, they must be passed by reference. If not you’ll get a syntax error (VBE notifies that, matter-of-factly, “Array argument must be ByRef”)

  3. Because arrays are passed as reference, the array that is passed (i.e. numsArr) is also modified. So in the subby macro, it doesn’t matter whether iterate through the numsArr or the funcArr arrays. They essentially point to the same array. So I can iterate through and debug.print either of them and get the same values.

Debugging functions

As I stated earlier, debugging functions can be difficult. Unlike macros, the functions don’t break at the line where the error occurred when called from the worksheet. So how do you debug them? Let’s look at some examples below

Runtime errors

Runtime errors are errors that cause a procedure to crash at runtime. This is what happens when a macro encounters such an error. It breaks and allows you to see which line of code the error occurred on. You can do this with function procedures as well. Let’s take a look at a few different options:

Immediate window: Using the immediate window (view -> immediate window), you can call the function like so: “debug.print ADDFIVE("hello world")” If no error ocurrs, the function will return the result in the immediate window. If one does occur, it will break on the line where the error occurred in VBE.

Test Macro: Another option you have is to run a test macro that calls the function like so:

Sub Test()

Range("A1").Value = ADDFIVE("hello world")

End Sub

Function ADDFIVE(val) As Long

ADDFIVE = val + 5

End Function

Running this code will give you an error in a similar error to using the immediate window. Now that we discussed some solutions for runtime errors, let’s discuss semantic errors.

Semantic errors

Semantic errors are errors that happen when a function returns a value, and so doesn’t have a runtime error, but does not return the value it should. These errors are the result of a bug in your code. Because there’s no runtime error, the code does not crash at any particular line. That makes these type of bugs significantly harder to find and debug. Let’s look at a strategy for finding such errors below:

Immediate window with debug.print statements: Like runtime errors, the immediate window can also be useful for looking at semantic errors. One strategy is to open the immediate window and use several debug.print statements in your code. You can use these statements to print the value of several variables as they’re occurring in your code to see if they have the value that they should. The good thing about this method is that these statements will be ignored when the function is called from the worksheet. So you can add them and not have to worry about your function not working as it should when it’s called from the worksheet.

Test macro with watches Let’s take a look at another test macro below:

Sub test()

Debug.Print funky()

End Sub

Function funky() As Boolean

Dim a As Long, b As Long, c As Long

a = -1
b = 2
c = 3

If a + b = c Then

    funky = True

Else

    funky = False

End If

End Function

From here, we can click the debug window and click “watch window”. With the watch window, you can create watches. Watches allow us to provide an expression and allows us to take certain action based on the options we select. Let’s assume that all variables in the funky function should have a value greater than zero. We can test for this by providing an expression like “a < 0”. For the procedure, select funky. And finally, select the option “break when true”. After we add this watch, we can run the Test procedure. This procedure will break at the line b = 2 because the value of a is less than zero. You can also add additional watches to check for other variables and other procedures. Using watch windows in this way lets you work with semantic errors in the same way that you’d work with runtime errors. And it can be very useful, especially for larger functions.

Advanced function topics

Private functions that can be used in different modules

If a function is private, it doesn’t appear as a function that you can use in the worksheet. Unfortunately, this also prevents you from using it in other modules other than the one it’s defined in. You can get around this by defining the function in a class module. While class modules sound advanced, and this may seem difficult, it’s actually pretty easy to do.

You start by inserting a class module into your project (Insert -> class module). The first thing we’re going to do in the properties window (view -> properties window) is change the name to UDF. Next, we’ll just recreate our initial ADDFIVE function in the class module below:

Function ADDFIVE(val As Long)
ADDFIVE = val + 5
End Function

With the function defined, open or insert a module in VBA. You can now create an instance of the UDF object with an object variable as you can see below:

Sub subby()

Dim u As UDF

Set u = New UDF

Debug.Print u.ADDFIVE(15)
'prints 20

Set u = Nothing

End Sub

A few things to note about this example:

  1. Since the u variable is an object, it must be instantiated. Objects are instantiated using the ‘new’ keyword. You can do this in the variable declaration like so: “Dim u As New UDF”. Using this syntax, you don’t need to set the variable to the object using the ‘set’ keyword. This syntax is more convenient but is not recommended.

  2. Since the u variable is an object, it should be terminated by being set to nothing when you’re done with it.

You can use the methods defined in this object in multiple modules without ever appearing in the Excel worksheet.

Windows API functions

You can functions to encapsulate the logic to utilize the Windows API to do a number of really advanced things, such as detecting the state of certain keys on the keyboard (e.g. numlock). This is really complicated though and out of the scope of this discussion. I did feel the need to mention that it was possible though. If you’re interested, you can google ‘Windows api VBA” to see some examples)

Conclusion

Thanks for reading! I hope you’ve learned by reading this post that functions can be very useful in VBA. I hope this post helps you write some of your own functions in the future!

🌐
ExcelHelp
excelhelp.com › home › general vba › general overview of vba functions
A General Overview of VBA Functions | Excel Help
May 23, 2020 - A function module can be developed to execute without receiving or returning any variables. Such modules can just be executed using the Call Function.
Top answer
1 of 5
35

Here are some of the different ways you can call things in Microsoft Access:

To call a form sub or function from a module

The sub in the form you are calling MUST be public, as in:

Public Sub DoSomething()
  MsgBox "Foo"
End Sub

Call the sub like this:

Call Forms("form1").DoSomething

The form must be open before you make the call.

To call an event procedure, you should call a public procedure within the form, and call the event procedure within this public procedure.

To call a subroutine in a module from a form

Public Sub DoSomethingElse()
  MsgBox "Bar"
End Sub

...just call it directly from your event procedure:

Call DoSomethingElse

To call a subroutine from a form without using an event procedure

If you want, you can actually bind the function to the form control's event without having to create an event procedure under the control. To do this, you first need a public function in the module instead of a sub, like this:

Public Function DoSomethingElse()
  MsgBox "Bar"
End Function

Then, if you have a button on the form, instead of putting [Event Procedure] in the OnClick event of the property window, put this:

=DoSomethingElse()

When you click the button, it will call the public function in the module.

To call a function instead of a procedure

If calling a sub looks like this:

Call MySub(MyParameter)

Then calling a function looks like this:

Result=MyFunction(MyFarameter)

where Result is a variable of type returned by the function.

NOTE: You don't always need the Call keyword. Most of the time, you can just call the sub like this:

MySub(MyParameter)
2 of 5
3

if pptCreator is a function/procedure in the same file, you could call it as below

call pptCreator()

Top answer
1 of 5
28

Because it clarifies the intent.

A Function clearly says "I'll have something for you when I return". The expectation is that a Function returns something, because that's what functions are meant to do.

A Sub clearly says "I'm doing something that you should expect to just eventually succeed". The expectation is that a Sub executes an action, alters some state, causes some side effects.

A Function that would be named DoSomething, is just as confusing as a Sub that would be named GetFoo: the intent is obscured, the very nature of the procedure conflicts with how it's advertised. I expect DoSomething to either succeed at doing something, or throw some error. Similarly, I expect GetFoo to, well, get me a Foo.


Because a non-returning function makes no sense.

In several programming languages, a Function (or semantically similar construct) that doesn't return a value in all code paths, can't even be compiled. Using a Function-without-a-return-value for everything in VBA sounds very much like abusing the language, just because VBA won't complain about it. As common wisdom tells us, it's not because we can, that we should.

Why return void, when you can return a bool everywhere, and not assign it?

public bool DoSomething()
{
    // do stuff...
    // ...and don't assign the return value.
    // woopsie, doesn't compile.
}

A VBA Sub procedure is like a C# void method: it's explicit about its non-returning nature, and that's a good thing.


Because static code analysis tools will complain.

The VBA compiler will notoriously not care if you write code where it's never clear whether your non-returning of an implicit return value is intentional or not.

When you do mean to return a value - and forget, because bugs happen all the time - how can you be sure that this one is legitimately non-returning, and that other one isn't? Without combing through the code and fully understanding everything it does and why, you can't tell. If you're lucky, you're looking at small, specialized functions that obviously do one thing, and do it well. Otherwise, you need to waste your time understanding what's going on, just to be sure of something that should already be obvious.

Static code analysis tools like Rubberduck (I maintain that project) will flag these functions, since they are potential bugs hiding in your code base, waiting to bite you:

2 of 5
10

I can think of a couple reasons off the top of my head.

  • It prevents the caller from trying to assign the non-existent return value to something:

    Sub example()
        Dim x
        x = Foo     '<-- Potential runtime error.
        x = Bar     '<-- Compile error, Expected Function or variable.
    End Sub
    
    Function Foo()
    End Function
    
    Sub Bar()
    End Sub
    
  • In Excel, it allows it to be used as a macro (assuming that it doesn't have arguments).

  • It's less efficient, because it has to push the return value onto the stack.
  • It's unclear to somebody else who is reading the code what the intention is.

    Function Foo()
        'Do some stuff
        'WTH is the return value not assigned?!
    End Function
    
  • It (should, assuming otherwise decent coding practices) signals that it should not have side effects. A Sub is expected to have side-effects.


Specifically regarding the edit.

I can use Function without declaring a return value and have the same, no?

This is not a correct statement. If you declare a function like this...

Function Foo()
    'Do some stuff
End Function

...it still has a return value - it is just implicit. The code above is exactly equivalent to:

Public Function Foo() As Variant
    'Do some stuff
End Function

VBA doesn't force you to explicitly declare the type of the return value (similar to how it doesn't require an explicit type for a Dim statement). That does not mean that it doesn't have one - it does.

🌐
GeeksforGeeks
geeksforgeeks.org › excel › function-and-sub-in-excel-vba
Function and Sub in Excel VBA - GeeksforGeeks
September 11, 2025 - A function in VBA can be defined as a procedure that executes a piece of code or instructions and post-execution, it returns the value of the tasks performed. A function is hence invoked using a variable.
🌐
Wise Owl
wiseowl.co.uk › vba-macros › guides › arguments-functions › functions
Writing and Using Functions in Excel Visual Basic
The difference between a subroutine and a function in VBA is that a function returns a value.
🌐
Dan Wagner Co
danwagner.co › dan wagner co › how to create a vba function and re-use it in many subroutines
How to Create a VBA Function and Re-use it in Many Subroutines | Dan Wagner Co
October 19, 2016 - This tutorial walks through an existing Subroutine and explains how to convert bits of repeated code into standalone Functions and Subroutines.
🌐
Microsoft Learn
learn.microsoft.com › en-us › office › vba › language › concepts › getting-started › calling-sub-and-function-procedures
Calling Sub and Function procedures (VBA) | Microsoft Learn
January 21, 2022 - The following example calls the MsgBox function by using named arguments. The return value is assigned to the variable. answer3 = MsgBox(Title:="Question 3", _ Prompt:="Are you happy with your salary?", Buttons:=4) ... Have questions or feedback about Office VBA or this documentation?
🌐
Corporate Finance Institute
corporatefinanceinstitute.com › home › resources › vba: sub vs function
VBA: Sub vs Function - Overview, Key Differences, How To Write
August 19, 2024 - A VBA function is similar to a sub procedure, only that the former can return a value whereas the latter cannot. It is a piece of code that can be called anywhere in the VBA Editor and eliminates the need to write the same lines of code every time.
🌐
Stack Overflow
stackoverflow.com › questions › 58907109 › how-do-i-call-a-function-return-a-value-in-vba
excel - How do I call a function/return a value in VBA? - Stack Overflow
VBA does not use Return - you have to define it as a Function (not a Sub) and then have the last line set the value of the function name to the value of y2 in order to return it.
🌐
Excel-Pratique.com
excel-pratique.com › en › vba › procedures_functions
VBA Course: Procedures and Functions
Function square(number As Double) square = number ^ 2 'The "square" function returns the value of "square" End Function Sub example() Dim result As Double result = square(9.876) 'The "result" variable receives the value returned by the function MsgBox result 'Display the result (in this case, the square of 9.876) End Sub
🌐
Stuartsplace
stuartsplace.com › information-technology › programming › vba › vba-functions
Stuart's Place | Information Technology | Programming | VBA | VBA Functions
A function in VBA is a block of statements that perform a specific task and returns a result, which can be used multiple times within a program. As with a lot of languages, VBA has a number of functions built in, however, it is also possible to create user defined functions.