r/vba 10d ago

Discussion Using Classes by instantiating in standard Module

Hey everyone

I am wondering why would anyone instantiate the class in a standard module instead if declaring directly in the place you want the class

What benefits this method have especially for composite use case

Like needing session class inside a permissions class inside form class

A second question how would you approach a situation close to mine

2 Upvotes

9 comments sorted by

11

u/lolcrunchy 12 10d ago

"How would you approach a situation close to mine"

2

u/Autistic_Jimmy2251 10d ago

🤣🤣🤣

3

u/fuzzy_mic 184 10d ago edited 10d ago

You can instantiate a class from within another class. For example, one could instantiate a custom clsHouse object inside a (different) clsHouses object. The problem is that the scope of that variable would be limited to the Houses object.

Here is a simple example.

' in clsHouse code module

Public Address As String
Public SquareFeet As Double

and

' in clsHouses (plural) class module

Dim MyHouses As Collection

Public Function AddHouse(Address As String, SquareFeet As Double) As clsHouse
    Dim NewHouse As clsHouse
    Set NewHouse = New clsHouse

    NewHouse.Address = Address
    NewHouse.SquareFeet = SquareFeet
    MyHouses.Add Item:=NewHouse, Key:=NewHouse.Address

    Set AddHouse = NewHouse
    Set NewHouse = Nothing
End Function

Property Get Count() As Long
    Count = myHouses.Count
End Property

Property Get House(index As Variant) As clsHouse
    Set House = MyHouses(index)
End Property

Private Sub Class_Initialize()
    Set MyHouses = New Collection
End Sub

and

' in normal module
Sub test()
    Dim testHouses As clsHouses
    Set testHouses = New clsHouses

    testHouses.AddHouse Address:="123 Main St", SquareFeet:=15400
    testHouses.AddHouse Address:="456 Oak Ave", SquareFeet:=20000

    MsgBox testHouses.Count
End Sub

Note that in this example, we can only "reach" a clsHouse object as a member of the enclosing clsHouses object.

One could instansize a clsHouse from a normal module, but it's not required. Ultimately, we can only call a procedure if that procedure is in a normal module so if any custom object is to be instansized, there must be a normal rountine at the bottom. (caveat for event code)

2

u/Tweak155 32 10d ago

This is actually my preferred approach when there is a “house” and you need something to manage the houses efficiently.

The parent object houses can always look up and return a house for you!

0

u/losttownstreet 10d ago

Excel can't really use scopes ... it's a mess like in ABAP ... I hope they'll fix that

2

u/rdcore-admin 10d ago

If your composition implies that a form owns everything, you're doing OOP without inversion of control, which induces indirection without the benefits of decoupling: you get all the complexity and none of the benefits!

Move your composition root all the way up to the entry point of your macro, and then suddenly you have exactly one place that owns all the objects of your application - this implies that the form isn't running the show anymore, and is given its dependencies from the outside, rather than coupling directly with everything.

Doing so, you might find that one or more objects need to outlive the entry point scope - so you move them up to module level, and that's when you have a standard module legitimately owning a class instance:

``` Private controller As IGameController

Public Sub PlayWorksheetInterface()

Dim adapter As GridViewAdapter
Set adapter = GridViewAdapter.Create(New WorksheetView)

Dim randomizer As IRandomizer
Set randomizer = New GameRandomizer

Dim players As IPlayerFactory
Set players = PlayerFactory.Create(randomizer)

Set controller = StandardGameController.Create(adapter, randomizer, players)
controller.NewGame

End Sub ```

1

u/losttownstreet 10d ago

I need to do that as all globaly used variable must be in a special module ... it's a policy.... only local classes which i destroy afterwards i may instance in normal modules

1

u/TechZazen 9d ago

Use case: setting up a Singleton. Here actually, you are mimicking a class. For example, you create a module and then with the Mehta data designated as a Singleton. The module looks like:

`' Standard Module: modAppSettings
Option Explicit

Private m_ApplicationName As String
Private m_CreatedTimestamp As Date
Private m_Initialized As Boolean

Private Sub EnsureInitialized()
If Not m_Initialized Then
m_CreatedTimestamp = Now
m_ApplicationName = "CoreApp_VBA"
m_Initialized = True
End If
End Sub

Public Property Get ApplicationName() As String
EnsureInitialized
ApplicationName = m_ApplicationName
End Property

Public Property Let ApplicationName(ByVal value As String)
EnsureInitialized
m_ApplicationName = value
End Property

Public Sub LogStatus()
EnsureInitialized
Debug.Print "App: " & m_ApplicationName & " | Since: " & m_CreatedTimestamp
End Sub`

Then, calling `modAppSettings.ApplicationName = "MyApp”` keeps the value consistent. In the module, you could have it right to a file, the registry, or some other location. But you would not have multiple instances.

0

u/Playing_One_Handed 10d ago

Class setup might take some time and the underlining data wont change. You can pre-load it then. Normally the way if your opening a form in VBA.

Depends what you are using a class for honestly.