Search This Blog

Showing posts with label typename. Show all posts
Showing posts with label typename. Show all posts

Friday, April 27, 2012

Interface Implementation in VBA and VB6

WARNING THIS CODE HAS A MEMORY LEAK: check UPDATE HERE

I have realized that setting Set mInstruments = Me in the Class inizialize method create a circular reference and so a memory leak. The new code is much better.

The Keyworkd Implements in VBA/VB6 allows you to Interface Implementation in VB6, which in turns allows for Polymorfism. This is indeed a great capabilites on VB6 language that is often overlooked.
While the VB6 version of interface implementation is not so elegant as the one from .NET environment, it still allows you to implement some nice pattern like the strategy or the abstract facotory one.
I will show you a very easy example on how to use it in VBA."
The Idea is to create an interface calle IInstrumets with just one property "Id", and have a Security class that implements its interface. You could also have a Fund, Porftolio or a Security Class that implements its interface. This wil allow for polymorfism.

Dim inst as IInstrument
Dim sec as Security
Dim fn as Fund

Set sec = new Security
Set fn = new Fund

Set inst = sec
Set inst = fn

As you can see, bot a security and a fund can be assigned to an Instruments object!
We first define a Class called IInstrument. The code is here

'This is an Interface for the Generic Financial Instrument

Public Property Get Id() As String
'Only Signature
End Property

Public Property Let Id(strId As String)
'Only Signature
End Property


We now create a new Class called Security that Implements the IInstrument one. This is a bit more tricky.
Once we implement an Interface, the Class that implements it in VB6 will declare those method as Private like that.

Private Property Get IInstrument_Id() As String
   IInstrument_Id = mId
End Property

This is a kind of unsual behaviour, because if I know that the Security class implements the IInstrument interface, I expect to have access to the same methods and property made available by the interface obejcts. For this reason, I usually code the Class using this rules
1) In the Class that implements the interface I declare at Class level a private object of the interface type

      Private mInstrument As IInstrument



2) In the constructor I assing the Obj to this instance. This will allow me to call the interface methods of my class

  Private Sub Class_Initialize()
    'I need to Access the IInstruments Methods
    Set mInstrument = Me
End Sub

3) I implement the interface methods as I normally do.

Private Property Get IInstrument_Id() As String

    IInstrument_Id = mId  
End Property

Private Property Let IInstrument_Id(strId As String)
   mId = strId
End Property

4) I crate public properties / methods mirroring the interface delegating their implementation to the
    mInstrument object
Public Property Get Id() As String

   Id = mInstrument.Id
End Property

Public Property Let Id(strId As String)
   mInstrument.Id = strId
End Property

Here you can find the Security Class Code


Implements IInstrument

Private mId As String
Private mInstrument As IInstrument

Public Ticker As String

Private Sub Class_Initialize()
  'I need to Access the IInstruments Methods
  Set mInstrument = Me
End Sub

Private Property Get IInstrument_Id() As String
       IInstrument_Id = mId
End Property


Private Property Let IInstrument_Id(strId As String)
  mId = strId
End Property


'Public Interface

Public Property Get Id() As String
     Id = mInstrument.Id
End Property

Public Property Let Id(strId As String)
  mInstrument.Id = strId
End Property

We can now test the code

Sub TestSecurity()
 Dim Sec1 As Security
 Dim Inst As IInstrument
 Dim Sec2 As Security
 Set Sec1 = New Security
 
 Sec1.Id = 10
 Sec1.Ticker = "MXEU"
 
 Set Inst = Sec1 'Upcast: A Security in an Instruments
 Debug.Print Inst.Id
 
 'DownCast, this should have been done explicit, but VBA does not support CType.
 'VB6 does. So instead of CType(Inst, "Security") we can do
 If TypeName(Inst) = "Security" Then
    Set Sec2 = Inst
    End If
 
 
 Set Sec2 = Inst

 Debug.Print Sec2.Id
 Debug.Print Sec2.Ticker
End Sub