Public variables are not needed inside a class. Declare them as Private.
Class modules and public variables
I am in the process of writing may first class modules. I am intrigued with the concept of class modules as kind of LEGO bricks which communicate with the outside world through Let and Get properties. This looks like a very robust concept of programming! But what about Public variables? If I use inside a class module without intention a variable name, which exists as Public variable in my project, then I could end up with a mess. Is there a way to seal off my class module, may be with an option, such that it behaves like an island and ignores all public variables?
4 answers
Sort by: Most helpful
-
-
Albert Kallal 4,806 Reputation points
2021-03-21T02:36:22.357+00:00 Well, public variables in your VBA code (not class) are in fact public.
but, when you use a class, then those public variables are public - but ONLY if you prefix the instance of the class.
In fact, MOST of my public members of a class OFTEN use public vars. The reason is simple:
Why write this:
Option Compare Database Option Explicit Private m_CompanyName As String Property Get CompanyName() As String CompanyName = m_CompanyName End Property Property Let CompanyName(v As String) m_CompanyName = v End Property
In above? You really don't need the m_CompanyName (the private member), and then the two code stubs (let/get) to set this up.
Why not just do this:
Option Compare Database Option Explicit Public CompanyName As String
Now in code you can do this:
Sub MyTest() Dim MyCustomer As New clsCustomer MyCustomer.CompanyName = "IBM" End Sub
You still get inteli-sense like this:
So any public variable you declare in that class as a base varibale name, and public? It will NOT be global your to your applcation and can ONLY be referenced by using a instance of that class, and also prefixing the name of the class in front.
And MORE interesting? in vb.net, and c#, this approach has quite much become the coding standard and norm now:
c#:
class Person { public string Name // property { get; set; } }
vb.net:
Class Person Public Property Name As String End Class
Turns out this also works in VBA - so I see little if any need to write a getter + setter for what amounts to a variable that has no code attached to that method.
So yes, I freely use public vars in those classes. But they still are separated out to each instance of the class, and are not public (global) in scope. So you can do this:
Dim Customer1 As New clsCustomer Customer1.CompanyName = "IBM" Dim Customer2 As New clsCustomer Customer2.CompanyName = "Microsoft"
So today, we see this trend both c# and vb.net, and I also been doing this in VBA for years. In fact, in most cases I don't even bother to write getters/setters for varibles. Only methods that have code do I write a actual get routine, and in fact in MOST cases I don't do that either.
So, for example, if we had something that returns company name and City? (lame example)
The you might see people write this:
Option Compare Database Option Explicit ' CLASS customer Public CompanyName As String Public City As String Property Get CompanyAndCity() As String CompanyAndCity = CompanyName & "," & City End Property Function CompanyCity() As String CompanyCity = CompanyName & "," & City End Function Sub SetCompanytoUpperCase() CompanyName = UCase(CompanyName) End Sub
in above for this example - I wrote the Company + city as a public Property (that's the default - you don't need the word public in front), then I have a choice. "Function" or a Property Get.
In fact, any function (or sub - they don't return values) you expose becomes a method of that class.
You see this in inteli-sense - and note how it shows the function (and sub) as a public method with a different icon:
So yes you are most free to declare and use public variables in that class - you NOT be able to use that variable without a instance of that class, and it is ONLY scoped to the instance of that class. And doing so as noted eliminates the need for getters/setters. I also do this in vb.net, and in c#? Well, you can do above, but you have to put in the get;set. (or leave the set out - it will be read only.
In fact, this is why I will sometimes use a public function to return a value - it is read only!
But, as a coding standard? Yes, you can freely declare public variables in your classes you create. They will not be global to the application, but only accessed by using a "instance" of that class.
Of Couse in a non class VBA module, then yes, public variables become global to all forms code and even your class instances you create in code. But this is NOT the case for public variables in those classes.
And thus in your class instance, if for some reason you DID need to use + consume a global var with the SAME name (and public)? You simply have to prefix that global (non class) variable with the code module's name. eg: Module1.CompanyName.
So, in that class instance, you always get the local scoped variable - even for public members. However, since you always have to create a instance of a class to use it? Then again, little issue exists as to which value/variable you get/use/have/work with in code.
I am rather comfortable recommending that you adopt public vars (members) as a coding practice when creating class objects in Access/VBA for public members - it will save lots of code and thus no need for getter/setters).
Regards,
Albert D. Kallal (Access MVP 2003-2017)
Edmonton, Alberta Canada -
Christoph Ruchti 1 Reputation point
2021-03-21T10:45:19.647+00:00 Hi Albert
Many thanks for your interesting explanation! This use of public variables declared at class level appears to be an attractive concept avoiding unneccessary LET and GET procedures. I will consider it further.
I had another situation in mind where the public variable is declared at project level:
' module at project level Option Explicit Public Temp As Double Public Energy As Double Public Cells As Collection Sub test() Dim oCell As clsCell Set Cells = New Collection Temp = 13 Set oCell = New clsCell oCell.p_Temp = Temp Cells.Add oCell Temp = 17 Set oCell = New clsCell oCell.p_Temp = Temp Cells.Add oCell Debug.Print Cells(1).p_Energy End Sub ' '------------------------------------------------------ ' Class module Option Explicit Private m_Temp As Double Private m_Energy As Double Public Property Let p_Temp(T As Double) m_Temp = T End Property Public Property Get p_Energy() As Double ' code computing the energy, for simplicity take m_Energy = 2 * m_Temp p_Energy = m_Energy End Property
This works fine as long as I work with discipline and use the "m_" prefix for member variables. The printed result is 26. If I happen to forget a prefix as below
Public Property Get p_Energy() As Double ' code computing the energy, for simplicity take m_Energy = 2 * Temp p_Energy = m_Energy End Property
then I get in trouble. The code works, but is producing an unexpected result (34). I am afraid of mistakes like this and was looking for a set-up, which simply prohibits such use of global variables in class modules.
Do you have a solution for this as well?
Kind regards
Christoph
-
Christoph Ruchti 1 Reputation point
2021-03-22T19:59:07.18+00:00 Thanks. Knowing that a desired feature / option does not exist also helps. It provides the justifictaion for own efforts.