Class modules and public variables

Christoph Ruchti 1 Reputation point
2021-03-20T08:53:27.203+00:00

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?

{count} votes

4 answers

Sort by: Most helpful
  1. Tom van Stiphout 1,621 Reputation points MVP
    2021-03-20T23:03:15.137+00:00

    Public variables are not needed inside a class. Declare them as Private.

    0 comments No comments

  2. Albert Kallal 4,651 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:

    79790-image.png

    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:

    79818-image.png

    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

    0 comments No comments

  3. 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


  4. 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.

    0 comments No comments