Why do we declare variables at the start of a module? - vba

As my first language and as completely taught from other's example I never questioned the standard practice in VBA of grouping all variable declarations at the start of the module, routine or function they are scoped to as in this example.
Sub Traditional()
Dim bVariable as Boolean
Dim OtherVariable
' Some code using OtherVariable goes here
'
' Now we use bVariable
bVariable = True
Do While bVariable
bVariable = SomeFunction()
Loop
End Sub
Now I'm learning that standard practice in other languages is to declare variables as close to where they are used as possible, like this:
Sub Defensive()
Dim OtherVariable as String
' Some code using OtherVariable goes here
'
' Now we use bVariable
Dim bVariable as Boolean
bVariable = True
Do While bVariable
bVariable = SomeFunction()
Loop
End Sub
This seems completely sensible to me as a defensive programming practice - in that it limits both span and live time (as explained in Code Complete), so I'm wondering if there is any reason for not doing the same in VBA? Possible reasons I can think of are memory, running time (e.g. repeatedly declaring inside a loop), tradition - arguably a good reason as there must be hundreds of thousands of VBA programmers who expect to see all used variables at the start of the routine. Are there any I've missed that might explain the benefit of this practice or at least where it came from?

I declare all my variables at the top. I think declaring them closer to first use masks (at least) two other problems that should be fixed first.
Procedures too long: If you're procedure is more than fits on a screen, perhaps it's doing too much and should be broken into smaller chunks. You'll also find that unit tests are way easier to write when your procedures are small and only do one thing.
Too many variables: If you have a bunch of related variables, consider using a custom class module or user-defined type. It will make the code more readable and easier to maintain.
If your procedures are short and you're using classes and UDTs, the benefits of declaring the variables at the point of use are lessened or eliminated.

I think both way are just different coding style in VBA
In old C Standard, all Declaration must be on the top, I think many people just adopt this habit and bring it into other PL such as VBA.
Declaring variable on the top is clear for short list of variable names. It will be unreadable for a long list of variable name
Declaring variable close to where it's being used is introduced later. I think this practice has a clear advantage over "declare on the top" for PLs that has optimizer or more scope than VBA. (Like you can declare variables where the scope is visible in a FOR loop only) Then the optimizer will change the scope for you. (In VBA words, it may change a GLOBAL variable to a PROCEDURE variable)
For VBA, no perference

Related

What are the risks of declaring a variable in the middle of the code?

I usually see in almost all of VBA codes all variables are declared after e.g. Sub/Function name line
I know and I used variable declaration in the middle of some of my codes (Not inside a loop) and saw no problems.
I usually avoided that because I see most of VBA example codes have them declared right after the first line. I just want to know what are the risks from an expert/experienced VB programmer point of view.
There are no risks of declaring it in the middle.
The effect of declaring a variable in the middle is that it can only be used after that point and not before (which is scope).
The lifetime of the variable is different: the variable is created (allocated and initialized to its respective flavour of zero) when you enter the procedure, but you may not actually use it until you reach its scope (the point in the procedure where it's declared).
Declaring inside or outside a loop does not make a difference in VB6/A as they do not have block scope, unlike VB.NET.
So there is no performance difference between the two approaches (because all variables are created when you enter the procedure), but there is a difference in usage (you may not use a created variable before its declaration line). If you think that distinction is helpful in making sure you are not using a variable wrongly, declare your variables only where needed. Otherwise you are free to pick any of the two approaches, just apply it consistently (it's probably not a good idea to declare most of the variables in the beginning and then some in the middle).
Declare your variables, when you actually need them. When you have all declarations lumped at the top of the procedure, refactoring becomes much harder. And when you want to double check your declaration as you read your code (or, perhaps, someone else), searching it at the top may be again quite inconvenient, unless you procedure is short.
I would try to declare variables in a location that conveys useful information to the next programmer, over and above being functionally correct. This normally means: follow the scoping rules of the language.
By declaring all variables at the top you are making them available (in scope) for the entire procedure. That increases the work for a reader in the future, trying to understand how they will be used. Better to have them as local as possible.
I would not declare them in a loop since that actually would not have significance in VB6/VBA - but someone else might find confusing or misleading, or worst case it may cause subtle bugs.
Of course remember that this is not the only coding practice that we should be mindful of - if the procedure is so long that the location of the variable declarations is a big problem, that's a really good sign that the procedure should be broken up into smaller discrete logical blocks. The variable declarations would just be a symptom, not the main cause.
IMO there were many bad programming practices back in the 90s and earlier when VBA/VB6 were invented, but the industry has significantly learned & improved since then. So code from that era (or inspired by it) is often not a good example.
Declaring your variables up front, at the top of your sub/function makes it easy for others (and perhaps for you if you come by the code after, say a month) to read and understand what your code needs to calculate, and what placeholders/variables are required for the code to function.
You can of course declare variables anywhere (as long as you remember not to use a variable unless you have actually declared it first). That can work, and it has no effect whatsoever on the performance of your code (unless your logic includes an early Exit Sub or Exit Function. In this case, there will be a difference in performance depending on if your code does actually allocate memory for the variables or not).
It just isn't good practice to declare some variables at the top then do some work, then declare another set of variables mid-code. There are exceptions of course. When the variable you declared mid-code is for a temporary use, or something like that.
Sub CalculateAge()
Dim BirthYear As Integer
Dim CurrentYear As Integer
'Code to fetch current year
'Code to get BirthYear from user/or document
'Code to report result
End Sub
Compare that with the following:
Sub CalculateAge2()
Dim BirthYear As Integer
'Code to ask the user or fetch the birth year from the document
Dim CurrentYear As Integer
'Code to populate currentYear
'Code to do the calculation and report result
End Sub
In the first example, there is a clear separation from variables and logic. In the second, everything is mixed.
The first example is a lot easier to read and understand, especially if you use a good naming convention.
If you look at how classes are written or defined, you will see properties usually are first declared, then methods/logic below. This is the common practice used to write code.
PS: In other languages, you can declare and assign variables in the same line. in C# or VB.Net you could say something like:
int Age = CurrentYear - BirthYear; //C#
Dim Age As Integer = CurrentYear - BirthYear 'VB.Net
This is great if you use a lot of temporary variables, that you don't intend to declare ahead of time or maybe it would be more clear if declared mid-logic. But that's not possible in VBA. You need a separate line to declare a variable, and another to assign a value. You end up with a lot of Dim ___ As ___ statements. You might as well move the declaration part somewhere else to reduce distraction while reading the logic. Again, this works best if you use a good and consistent naming convention. If not, you end up in a worse situation like:
Dim w As Integer
Dim a As Integer
a = 42 'we don't know what this variable is for
'but we know its type from the previous line
Some_Lines_Of_code_And_Logic
' more code
' more code
w = 2 'we don't know what (w) is for, and we have to
'look up its declaration to get a hint
'which might be tedious

VBA Best Practices: working with small subs and functions, passing values between routines

I learned from internet that our vba macros (subs and functions) should be more or less the size of the screen.
But all my code is written exactly in the opposite: a have a huuuge main sub that calls functions and small subs.
My question is: if I decide to convert my main huge sub into small subs (sub1, sub2, sub3, etc), then what should be the best way to keep the value of a variable that was assigned in sub1 and use it in sub2, that was assigned in sub2 and use it in sub3, and so on? If I have no answer to this question, I am going to save those values in a sheet, but maybe this way is going to cause me trouble that I cannot see by now. Thanks for any help.
A Sub or a Function should have a single and clear purpose, told by its name. If you break down your code in such chunks, you will know what information those methods will need and deliver. At the same time they will become smaller. If you have to choose between size and clarity, go for clarity.
Do NOT put your values in a sheet. That is just a different and less efficient way of using global variables, which is something you should avoid (not at all cost, but almost).
Both methods below would work. In my personal opinion, method 1 keeps code more simple (you avoid to pass big bunches of parameters to each macro) but depending on your need you might choose one or the other.
Global variables
Your code would look something like this:
'Global variables declaration
Dim a As Integer
Dim b As Integer
'
Public Sub mainRoutine()
setA '<-- call first macro
setB '<-- call second macro
MsgBox a + b '<-- show A + B (2 + 3 = 5)
End Sub
'code of sub-routines
Private Sub setA()
a = 2 '<-- since a is global, it will keep the value
End Sub
Private Sub setB()
b = 3 '<-- since b is global, it will keep the value
End Sub
Please note: global means that the value of this variable will live for all execution of your program. Memory will be released once the program ends.
Pass variables as ByRef parameters
Public Sub mainRoutine()
Dim a As Integer '<-- a is local
a = 2 '<-- setting a to 2
setA a '<-- passing a as ByRef parameter
MsgBox a '<-- a is now 3
End Sub
Private Sub setA(ByRef a As Integer)
a = 3 '<-- setting a as 3.
End Sub
Of course, the above method would only allow to keep a = 2/3 during the execution of mainRoutine. But if at some point you execute another macro called by another stack (for example another button in the spreadsheet), you wouldn't be able to access the value of a as you would in method 1.
Important: no, variables on the spreadsheet is not a good idea, unless you don’t need to keep the value after closing and reopening the spreadsheet (in that case you would be using the spreadsheet as a sort of database).
VBA can be considered as an object oriented programming language (OOP).It has 3 of the 4 pillars of OOP:
Abstraction
Encapsulation
Polymorphism
This is discussed in Is VBA an OOP language, and does it support polymorphism?
OOP means understanding the SOLID principles.
Single Responsibility Principle
Open Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Best practice is to adhere to these principles and the first is the Single Responsibility Principle.
This states that your functions/subs should have one responsibility and focus on doing one thing.
Advantages (amongst others):
The reduced code complexity and dependencies mean:
1) Easier to debug as your track down which sub/function the error is raised in
2) Units tests can be more easily be built around code that is based on single responsibility.
3) Can be more easily slotted into a wider code base
To use variables between subs/functions consider:
1) Either public variables, and/or
2) Passing variables as arguments
Other info:
OOP VBA pt.1: Debunking Stuff

Excel VBA store functions or subroutines in an array

In C/C++, when I have a bunch of functions (pointers), I can store them in an array or a vector and call some of them together in a certain order. Can something similar be done in VBA?
Thanks!
Yes, but I don't recommend it. VBA isn't really built for it. You've tagged this question with Excel, so I will describe how it is done for that Office Product. The general concept applies to most of the Office Suite, but each different product has a different syntax for the Application.Run method.
First, it's important to understand the two different methods of dynamically calling a procedure (sub/function) and when to use each.
Application.Run
Application.Run will either run a subroutine or call a function that is stored in a standard *.bas module.
The first parameter is the name of the procedure (passed in as a string). After that, you can pass up to 30 arguments. (If your procedure requires more than that, refactor for the love of code.)
There are two other important things to note about Application.Run.
You cannot use named arguments. Args must be passed by position.
Objects passed as arguments are converted to values. This means you could experience unexpected issues if you try to run a procedure that requires objects that have default properties as arguments.
Public Sub Test1()
Application.Run "VBAProject.Module1.SomeFunction"
End Sub
The takeaway:
Use Application.Run when you're working with a standard module.
VBA.Interaction.CallByName
CallByName executes a method of an object, or sets/gets a property of an object.
It takes in the instance of the object you want to call the method on as an argument, as well as the method name (again as a string).
Public Sub Test2()
Dim anObj As SomeObject
Dim result As Boolean
result = CallByName(anObj, "IsValid")
End Sub
The takeaway:
Use CallByName when you want to call a method of a class.
No pointers.
As you can see, neither of these methods use actual pointers (at least not externally). They take in strings that they then use to find the pointer to the procedure that you want to execute. So, you'll need to know the exact name of the procedure you want to execute. You'll also need to know which method you need to use. CallByName having the extra burden of requiring an instance of the object you want to invoke. Either way, you can stores these names as strings inside of an array or collection. (Heck, even a dictionary could make sense.)
So, you can either hard code these as strings, or attempt to extract the appropriate procedure names at runtime. In order to extract the procedure names, you'll need to interface with the VBIDE itself via the Microsoft Visual Basic for Applications Extensibility library. Explaining all of that here would require far too much code and effort, but I can point you to some good resources.
Articles & SE Questions:
Chip Pearson's Programming The VBA Editor
Extending the VBA Extensibility Library
Ugly workaround to get the vbext_ProcKind is breaking encapsulation
Automagic testing framework for VBA
How to get the procedure or function name at runtime
Import Lines of Code
Meta Programming in VBA: The VBIDE and Why Documentation is Important
The code from some of my Qs & As:
vbeCodeModule
vbeProcedure
vbeProcedures
A workaround is to enumerate and use a switch statement. You can store enumerated types (longs) in an array. E.g.:
Enum FType
func1
func2
func3
End Enum
Sub CallEnumFunc(f As FType, arg As String)
Select Case f
Case func1: MyFunction1(arg)
Case func2: MyFunction2(arg)
Case func3: MyFunction3(arg)
End Select
End Sub
Dim fArray(1) As FType
fArray(0) = func1
fArray(1) = func2
CallEnumFunc fArray(1), "blah"

Is it possible to use Variables without DIM in VB.NET?

Is it in VB.NET possible to use variables without the need of use DIM?
now I have to use the variables like this:
dim a = 100
dim b = 50
dim c = a + b
I want to be able to use vars in this way:
a=100
b=50
c=a+b 'c contains 150
I think in VB6 and older VB this was possible, but I am not sure.
As far as what #Konrad said, he is correct. The answer, buried in all his caveat emptors, is the answer of "yes", you can absolutely do this in VB.NET by declaring Option Explicit Off. That said, when you do a=1, the variable a is NOT an Integer - it is an Object type. So, you can't then do c = a + b without compiler errors. You'll need to also declare Option Strict Off. And at that point, you throw away all the benefits of a compiler. Don't do it.
As an alternative, with Option Infer On, Dim behaves the same as C#'s var keyword and gives you a lot of advantages if you're trying to save on typing.
You have a fundamental misunderstanding of how VB is supposed to work. The Dim statements are there to help you. Your wish to elide them is misplaced.
The compiler enforces variable declaration so that it can warn you when you have accidentally misspelt a variable name, thus inadvertently creating a new variable, and is required to enforce type safety. Without variable declaration, VB code becomes an unreadable, unmaintainable mess.
Incidentally, the same was true in VB6, and you should have used Option Explicit in VB6 to make the compiler force you to use them properly. This option still exists in VB.NET but switching it off has no advantage, and a whole lot of disadvantages so don’t do it – instead, learn to appreciate explicit variable declarations, and all the help that the compiler is giving you through them.

When to use a Class in VBA?

When is it appropriate to use a class in Visual Basic for Applications (VBA)?
I'm assuming the accelerated development and reduction of introducing bugs is a common benefit for most languages that support OOP. But with VBA, is there a specific criterion?
It depends on who's going to develop and maintain the code. Typical "Power User" macro writers hacking small ad-hoc apps may well be confused by using classes. But for serious development, the reasons to use classes are the same as in other languages. You have the same restrictions as VB6 - no inheritance - but you can have polymorphism by using interfaces.
A good use of classes is to represent entities, and collections of entities. For example, I often see VBA code that copies an Excel range into a two-dimensional array, then manipulates the two dimensional array with code like:
Total = 0
For i = 0 To NumRows-1
Total = Total + (OrderArray(i,1) * OrderArray(i,3))
Next i
It's more readable to copy the range into a collection of objects with appropriately-named properties, something like:
Total = 0
For Each objOrder in colOrders
Total = Total + objOrder.Quantity * objOrder.Price
Next i
Another example is to use classes to implement the RAII design pattern (google for it). For example, one thing I may need to do is to unprotect a worksheet, do some manipulations, then protect it again. Using a class ensures that the worksheet will always be protected again even if an error occurs in your code:
--- WorksheetProtector class module ---
Private m_objWorksheet As Worksheet
Private m_sPassword As String
Public Sub Unprotect(Worksheet As Worksheet, Password As String)
' Nothing to do if we didn't define a password for the worksheet
If Len(Password) = 0 Then Exit Sub
' If the worksheet is already unprotected, nothing to do
If Not Worksheet.ProtectContents Then Exit Sub
' Unprotect the worksheet
Worksheet.Unprotect Password
' Remember the worksheet and password so we can protect again
Set m_objWorksheet = Worksheet
m_sPassword = Password
End Sub
Public Sub Protect()
' Protects the worksheet with the same password used to unprotect it
If m_objWorksheet Is Nothing Then Exit Sub
If Len(m_sPassword) = 0 Then Exit Sub
' If the worksheet is already protected, nothing to do
If m_objWorksheet.ProtectContents Then Exit Sub
m_objWorksheet.Protect m_sPassword
Set m_objWorksheet = Nothing
m_sPassword = ""
End Sub
Private Sub Class_Terminate()
' Reprotect the worksheet when this object goes out of scope
On Error Resume Next
Protect
End Sub
You can then use this to simplify your code:
Public Sub DoSomething()
Dim objWorksheetProtector as WorksheetProtector
Set objWorksheetProtector = New WorksheetProtector
objWorksheetProtector.Unprotect myWorksheet, myPassword
... manipulate myWorksheet - may raise an error
End Sub
When this Sub exits, objWorksheetProtector goes out of scope, and the worksheet is protected again.
I think the criteria is the same as other languages
If you need to tie together several pieces of data and some methods and also specifically handle what happens when the object is created/terminated, classes are ideal
say if you have a few procedures which fire when you open a form and one of them is taking a long time, you might decide you want to time each stage......
You could create a stopwatch class with methods for the obvious functions for starting and stopping, you could then add a function to retrieve the time so far and report it in a text file, using an argument representing the name of the process being timed. You could write logic to log only the slowest performances for investigation.
You could then add a progress bar object with methods to open and close it and to display the names of the current action, along with times in ms and probable time remaining based on previous stored reports etc
Another example might be if you dont like Access's user group rubbish, you can create your own User class with methods for loging in and out and features for group-level user access control/auditing/logging certain actions/tracking errors etc
Of course you could do this using a set of unrelated methods and lots of variable passing, but to have it all encapsulated in a class just seems better to me.
You do sooner or later come near to the limits of VBA, but its quite a powerful language and if your company ties you to it you can actually get some good, complex solutions out of it.
Classes are extremely useful when dealing with the more complex API functions, and particularly when they require a data structure.
For example, the GetOpenFileName() and GetSaveFileName() functions take an OPENFILENAME stucture with many members. you might not need to take advantage of all of them but they are there and should be initialized.
I like to wrap the structure (UDT) and the API function declarations into a CfileDialog class. The Class_Initialize event sets up the default values of the structure's members, so that when I use the class, I only need to set the members I want to change (through Property procedures). Flag constants are implemented as an Enum. So, for example, to choose a spreadsheet to open, my code might look like this:
Dim strFileName As String
Dim dlgXLS As New CFileDialog
With dlgXLS
.Title = "Choose a Spreadsheet"
.Filter = "Excel (*.xls)|*.xls|All Files (*.*)|*.*"
.Flags = ofnFileMustExist OR ofnExplorer
If OpenFileDialog() Then
strFileName = .FileName
End If
End With
Set dlgXLS = Nothing
The class sets the default directory to My Documents, though if I wanted to I could change it with the InitDir property.
This is just one example of how a class can be hugely beneficial in a VBA application.
I use classes if I want to create an self-encapsulated package of code that I will use across many VBA projects that come across for various clients.
I wouldn't say there's a specific criterion, but I've never really found a useful place to use Classes in VBA code. In my mind it's so tied to the existing models around the Office apps that adding additional abstraction outside of that object model just confuses things.
That's not to say one couldn't find a useful place for a class in VBA, or do perfectly useful things using a class, just that I've never found them useful in that environment.
For data recursion (a.k.a. BOM handling), a custom class is critically helpful and I think sometimes indispensable. You can make a recursive function without a class module, but a lot of data issues can't be addressed effectively.
(I don't know why people aren't out peddling BOM library-sets for VBA. Maybe the XML tools have made a difference.)
Multiple form instances is the common application of a class (many automation problems are otherwise unsolvable), I assume the question is about custom classes.
I use classes when I need to do something and a class will do it best:) For instance if you need to respond to (or intercept) events, then you need a class. Some people hate UDTs (user defined types) but I like them, so I use them if I want plain-english self-documenting code. Pharmacy.NCPDP being a lot easier to read then strPhrmNum :) But a UDT is limited, so say I want to be able to set Pharmacy.NCPDP and have all the other properties populate. And I also want make it so you can't accidentally alter the data. Then I need a class, because you don't have readonly properties in a UDT, etc.
Another consideration is just simple readability. If you are doing complex data structures, it's often beneficial to know you just need to call Company.Owner.Phone.AreaCode then trying to keep track of where everything is structured. Especially for people who have to maintain that codebase 2 years after you left:)
My own two cents is "Code With Purpose". Don't use a class without a reason. But if you have a reason then do it:)
You can also reuse VBA code without using actual classes. For example, if you have a called, VBACode. You can access any function or sub in any module with the following syntax:
VBCode.mysub(param1, param2)
If you create a reference to a template/doc (as you would a dll), you can reference code from other projects in the same way.
Developing software, even with Microsoft Access, using Object Oriented Programming is generally a good practice. It will allow for scalability in the future by allowing objects to be loosely coupled, along with a number of advantages. This basically means that the objects in your system will be less dependent on each other, so refactoring becomes a lot easier. You can achieve this is Access using Class Modules. The downside is that you cannot perform Class Inheritance or Polymorphism in VBA. In the end, there's no hard and fast rule about using classes, just best practices. But keep in mind that as your application grows, the easier it is to maintain using classes.
As there is a lot code overhead in using classes in VBA I think a class has to provide more benefit than in other languages:
So this are things to consider before using a class instead of functions:
There is no class-inheritance in vba. So prepare to copy some code when you do similar small things in different classes. This happens especially when you want to work with interfaces and want to implement one interfaces in different classes.
There are no built in constructors in vba-classes. In my case I create a extra function like below to simulate this. But of curse, this is overhead too and can be ignored by the one how uses the class. Plus: As its not possible to use different functions with the same name but different parameters, you have to use different names for your "constructor"-functions. Also the functions lead to an extra debug-step which can be quite annoying.
Public Function MyClass(ByVal someInit As Boolean) As MyClassClass
Set MyClass = New MyClassClass
Call MyClass.Init(someInit)
End Function
The development environment does not provide a "goto definition" for class-names. This can be quite annoying, especially when using classes with interfaces, because you always have to use the module-explorer to jump to the class code.
object-variables are used different to other variable-types in different places. So you have to use a extra "Set" to assign a object
Set varName = new ClassName
if you want to use properties with objects this is done by a different setter. You have to use "set" instead of "let"
If you implement an interface in vba the function-name is named "InterfaceName_functionName" and defined as private. So you can use the interface function only when you cast the Variable to the Interface. If you want to use the function with the original class, you have to create an extra "public" function which only calls the interface function (see below). This creates an extra debug-step too.
'content of class-module: MyClass
implements IMyInterface
private sub IMyInterface_SomeFunction()
'This can only be called if you got an object of type "IMyInterface"
end function
private sub IMyInterface_SomeFunction()
'You need this to call the function when having an object of the type "MyClass"
Call IMyInterface_SomeFunction()
end function
This means:
I !dont! use classes when they would contain no member-variables.
I am aware of the overhead and dont use classes as the default to do things. Usually functions-only is the default way to do things in VBA.
Examples of classes I created which I found to be useful:
Collection-Classes: e.g. StringCollection, LongCollection which provide the collection functionality vba is missing
DbInserter-Class: Class to create insert-statements
Examples of classes I created which I dont found to be useful:
Converter-class: A class which would have provided the functionality for converting variables to other types (e.g. StringToLong, VariantToString)
StringTool-class: A class which would have provided some functionality for strings. e.g. StartsWith
You can define a sql wrapper class in access that is more convenient than the recordsets and querydefs. For example if you want to update a table based on a criteria in another related table, you cannot use joins. You could built a vba recorset and querydef to do that however i find it easier with a class. Also, your application can have some concept that need more that 2 tables, it might be better imo to use classes for that. E.g. You application track incidents. Incident have several attributes that will hold in several tables {users and their contacts or profiles, incident description; status tracking; Checklists to help the support officer to reply tonthe incident; Reply ...} . To keep track of all the queries and relationships involved, oop can be helpful. It is a relief to be able to do Incident.Update(xxx) instead of all the coding ...
In VBA, I prefer classes to modules when:
(frequent case) I want multiple simultaneous instances (objects) of a common structure (class) each with own independent properties.
Example:Dim EdgeTabGoogle as new Selenium.EdgeDriverDim EdgeTabBing as new
Selenium.EdgeDriver'Open both, then do something and read data to and from both, then close both
(sometimes) I want to take advantage of the Class_Initialize and Class_Terminate automatic functions
(sometimes) I want hierarchical tree of procedures (for just variables a chain of "Type" is sufficient), for better readability and Intellisense
(rarely) I want public variables or procedures to not show in Intellisense globally (unless preceded by the object name)
I don't see why the criteria for VBA would be any different from another language, particularly if you are referring to VB.NET.