HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Parameterised Constructors

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
constructorsparameterisedstackoverflow

Problem

Finally, Parameterised Constructors are possible in VBA.

Background:

One rainy day, I came up with an idea: take a static class and expose one property as default (like it was done in the Reverse for each loop for the .Item() property. This time however, I thought I'll make a PieceOfMe() Get Property the default which is capable of

-
taking no parameters aka. acting like a static class

-
optional parameters aka. Let property of VBA class modules - is it possible to have multiple arguments?

-
ParamArray * careful with this one though! You've got to trust yourself passing a ParamArray...

Pros

-
simple to implement and use

-
Parameterised Constructors ;)

Cons - as far as I am concern at this point...

-
Default member as well as PieceOfMe() doesn't support a full intelli-sense. It shows the expected parameters count but it doesn't tell what type etc. I think that's fixable though haven't had time yet to play with it.

-
No way to hide PieceOfMe() from intelli-sense and Object Browser

-
Always have to export your class (or write it in) to a text editor and add attributes etc.

Let's go!

Constructor.cls

VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "Constructor"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Explicit

Private myName as String

Private Sub Class_Initialize()
    myName = Cstr(Int((100) * rnd + 1))
End Sub

Public Property Get Name() as String
    Name = myName
End Property

Public Property Get PieceOfMe(Optional value as String) As Constructor
    Attribute Item.VB_UserMemId = 0
    myName = value
    Set PieceOfMe = Me
End Property


This class basically is the best to start off with:

-
it's made static by VB_PredeclaredId = True

-
Private myName as String is private because I wanted my encapsulation to only allow the default member -> PieceOfMe() to assign a value via the parameter passed.

-
`Optio

Solution

My assumption is that your goal is to mimick constructors in a language which lacks them

If I understand correctly, this is a freaking sweet idea! If the class need the default member for anything else, why WOULDN'T you want a constructor?

I have to agree with @MatsMug that the examples you've got are somewhat confusing - the class is named Constructor and the constructor is named PieceOfMe? I'd suggest a more concrete example, like the CircleShape class below.

I'd advise the removal of the randomized parameter and the use of the static instance for anything but constructing new instances. They seem unrelated to the underlying concept, which is mimicking constructors in a language that lacks them. In fact, it seems more like writing Set myCircle = CircleShape (assigns the static, named instance of CircleShape to myCircle) when you intended to call the empty constructor Set myCircle = CircleShape() (calls Constructor with none of the optional parameters, creating a new defaulted instance) would be a pitfall to avoid.

A concrete example, the CircleShape class with a default Constructor method:

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "CircleShape"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Compare Database

Private m_Radius As Double
Private Const PI = 3.1415926535898

Public Property Get Constructor(Optional Radius As Double = 1) As CircleShape
Attribute Constructor.VB_UserMemId = 0
'This is the default member
    Set Constructor = New CircleShape
    Constructor.Radius = Radius
End Property

Public Property Get Radius() As Double
    Radius = m_Radius
End Property

Public Property Let Radius(value As Double)
    m_Radius = value
End Property

Public Property Get Area() As Double
    Area = m_Radius * PI
End Property


And testing the class:

Public Sub Main()
    Dim myCircle As CircleShape

    Set myCircle = CircleShape(4.75)
    Debug.Print "4.75 inch circle area: " & myCircle.Area

    Set myCircle = CircleShape()
    Debug.Print "Unit circle area: " & myCircle.Area
End Sub


I implemented the other two examples as a RectangleShape(Optional Length As Double = 0, Optional Width As Double = 0 and HyperCubeShape(ParamArray arr() As Variant) with the intent of HyperCubeShape(numberOfDimensions As Long, lengthDim1 As Double, lengthDim2 As Double, ...) to test them out and they work as advertised. Can't wait to see if you can figure out a way of intellisensing the ParamArray!

Code Snippets

VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
END
Attribute VB_Name = "CircleShape"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
Option Compare Database

Private m_Radius As Double
Private Const PI = 3.1415926535898

Public Property Get Constructor(Optional Radius As Double = 1) As CircleShape
Attribute Constructor.VB_UserMemId = 0
'This is the default member
    Set Constructor = New CircleShape
    Constructor.Radius = Radius
End Property

Public Property Get Radius() As Double
    Radius = m_Radius
End Property

Public Property Let Radius(value As Double)
    m_Radius = value
End Property

Public Property Get Area() As Double
    Area = m_Radius * PI
End Property
Public Sub Main()
    Dim myCircle As CircleShape

    Set myCircle = CircleShape(4.75)
    Debug.Print "4.75 inch circle area: " & myCircle.Area

    Set myCircle = CircleShape()
    Debug.Print "Unit circle area: " & myCircle.Area
End Sub

Context

StackExchange Code Review Q#67825, answer score: 6

Revisions (0)

No revisions yet.