Object-Oriented-Programming with CATScript
Object-oriented programming (OOP) is not commonly used in CATScript macros, or at least, there is not so much information and sample-code available on the web or in various books and documentation I looked at.
However, CATScript - similar to VBS - does support class declarations, so there is no excuse for an adventurous programmers to not use it.
OOP What is it good for?
Some of the benefits of using object-oriented programming in CATScript are:
- Encapsulation and derivation, which makes the code more organized
- Cleaner and more reusable code blocks and classes
- Public functions that can be lay-outed quite similar to the CATIA API
- Object-oriented programming requires more thought before development, but it is easier to extend and adopt later in the course of the development process.
In modern programming languages which support OOP like c++, classes can have a variety of features, including inheritance, polymorphism, encapsulation, abstraction, and more. In VBA or CATScript however, only a small sub-set of these features is available.
ChatGPT - Let’s give it a trial
Here is an interactive ChatGPT Q&A session to find out more about OOP in combination with VBA / CATScript.
Here is a basic class template in VBA that demonstrates some of the features available in Object-Oriented Programming (OOP):
' Define the class name
Class MyClass
' Define the private variables
Private var1 As Integer
Private var2 As String
' Define the public properties
Public Property Get Property1() As Integer
Property1 = var1
End Property
Public Property Let Property1(value As Integer)
var1 = value
End Property
Public Property Get Property2() As String
Property2 = var2
End Property
Public Property Let Property2(value As String)
var2 = value
End Property
' Define the public methods
Public Sub Method1()
' Do something
End Sub
Public Function Method2(parameter1 As Integer, parameter2 As String) As String
' Do something with the parameters
Method2 = parameter2 & parameter1
End Function
End Class
This class has two private variables (var1 and var2) and two public properties (Property1 and Property2) that can be used to access and modify these variables.
It also has two public methods (Method1 and Method2) that can be used to perform some actions.
Sure, here is the updated class template that includes Class_Initialize and Class_Terminate events:
' Define the class name
Class MyClass
' Define the private variables
Private var1 As Integer
Private var2 As String
' Define the public properties
Public Property Get Property1() As Integer
Property1 = var1
End Property
Public Property Let Property1(value As Integer)
var1 = value
End Property
Public Property Get Property2() As String
Property2 = var2
End Property
Public Property Let Property2(value As String)
var2 = value
End Property
' Define the public methods
Public Sub Method1()
' Do something
End Sub
Public Function Method2(parameter1 As Integer, parameter2 As String) As String
' Do something with the parameters
Method2 = parameter2 & parameter1
End Function
' Define the Class_Initialize event
Private Sub Class_Initialize()
' Do something when the class is initialized
var1 = 0
var2 = ""
End Sub
' Define the Class_Terminate event
Private Sub Class_Terminate()
' Do something when the class is terminated
End Sub
End Class
The Class_Initialize event is called automatically when an instance of the class is created, and can be used to initialize any properties or variables that need to be set when the object is created.
The Class_Terminate event is called automatically when the instance of the class is destroyed, and can be used to perform any cleanup tasks that need to be done before the object is destroyed, such as closing files or releasing resources.
These events can be used to ensure that the object is properly initialized and cleaned up, and can help prevent errors and memory leaks in your code.
Sure, here’s an example of how you can instantiate the MyClass class in CATScipt:
Sub Example()
' Declare a variable of type MyClass
Dim myObject As MyClass
' Instantiate the class
Set myObject = New MyClass
' Use the properties and methods of the class
myObject.Property1 = 10
myObject.Property2 = "Hello, world!"
myObject.Method1
Dim result As String
result = myObject.Method2(5, "Parameter: ")
Debug.Print result
' Destroy the object when done
Set myObject = Nothing
End Sub
In this example, we first declare a variable myObject of type MyClass. We then instantiate the class using the New keyword and assign the instance to the myObject variable using the Set keyword.
We can then use the properties and methods of the class as needed, such as setting Property1 and Property2, calling Method1 and passing arguments to Method2. Finally, we set myObject to Nothing to release the memory used by the object.
Note that the Class_Initialize event will be called automatically when the New keyword is used to create the instance, and the Class_Terminate event will be called automatically when the myObject variable is set to Nothing or goes out of scope.
Supported or not supported ?
Can I overload functions? in other words can I do this:
Public Sub Method1(ByVal str As String)
' Do something
End Sub
Public Sub Method1(ByVal i As Integer)
' Do something
End Sub
No, in VBA you cannot have two methods with the same name and parameter list, even if the data types of the parameters are different. This is because VBA/CATScript does not support method overloading, which is a feature found in many other programming languages that allows methods to have the same name but different parameter lists.
If you try to define two methods with the same name and parameter list, you will get a compile-time error. To avoid this error, you can either give the methods different names, or you can use optional parameters to simulate method overloading. For example:
Public Sub Method1(ByVal str As String, Optional ByVal i As Integer)
If Not IsMissing(i) Then
' Do something with str and i
Else
' Do something with str
End If
End Sub
In this example, the i parameter is optional, so you can call the method with either one or two arguments. If you call the method with only one argument, the i parameter will be set to the default value of 0. If you call the method with two arguments, the i parameter will be set to the second argument.
Yes, in VBA you can use variable arguments in a procedure or function by using the ParamArray keyword. This allows you to pass an arbitrary number of arguments to the procedure or function.
Here is an example of a procedure that takes a variable number of arguments:
Sub Example(ParamArray args() As Variant)
Dim i As Integer
For i = LBound(args) To UBound(args)
Debug.Print args(i)
Next i
End Sub
In this example, the ParamArray keyword is used to declare a variable-length argument list named args. The LBound and UBound functions are used to loop through the array of arguments and print each one to the Immediate window.
You can call this procedure with any number of arguments, like this:
Example "Hello", "world", 123, True
Yes, you can use the “New” keyword to create a new instance of a custom class in VBA, just like in other object-oriented programming languages. Here’s an example:
' Define a custom class called "myCustomClass"
Class myCustomClass
Private myString As String
' Constructor method that sets the value of "myString"
Public Sub Class_Initialize()
myString = ""
End Sub
' Constructor method that takes a string argument and sets the value of "myString"
Public Sub New(s As String)
myString = s
End Sub
' Public method that returns the value of "myString"
Public Function GetString() As String
GetString = myString
End Function
End Class
' Create a new instance of "myCustomClass" and pass a string argument to the constructor
Dim myClass As New myCustomClass("test")
' Call the "GetString" method of the new instance and display the result in a message box
MsgBox myClass.GetString()
This code creates a new instance of the “myCustomClass” class, passing the string “test” as an argument to the constructor. It then calls the “GetString” method of the new instance to retrieve the value of the “myString” field and displays the result in a message box.
Syntax checking
Is this class syntactically correct?
This code contains 2 fundamental errors, I would like to know what happens here:
' Define the class name
Class CustomStrArray
' Define the private variables
Private csa() As String
' Define the public properties
Public Property Get Count() As String
Count = UBound(csa)
End Property
' Define the public methods
Public Sub Add(ByVal str As String)
ReDim (UBound(csa)+1)
csa(UBound(csa)+1) = str
End Sub
' Define the Class_Initialize event
Private Sub Class_Initialize()
' Do something when the class is initialized
ReDim csa(0)
End Sub
' Define the Class_Terminate event
Private Sub Class_Terminate()
ReDim csa(0)
End Sub
End Class
No, this class has a syntax error in the Add method. The ReDim statement is not using the correct syntax to preserve the existing values in the array. Here’s the corrected code:
Class CustomStrArray
' Define the private variables
Private csa() As String
' Define the public properties
Public Property Get Count() As Long
Count = UBound(csa) + 1
End Property
' Define the public methods
Public Sub Add(ByVal str As String)
ReDim Preserve csa(UBound(csa) + 1)
csa(UBound(csa)) = str
End Sub
' Define the Class_Initialize event
Private Sub Class_Initialize()
' Do something when the class is initialized
ReDim csa(0)
End Sub
' Define the Class_Terminate event
Private Sub Class_Terminate()
ReDim csa(0)
End Sub
End Class
Changes made to the original code:
- In the Count property, the return type has been changed from String to Long.
- In the Add method, the ReDim statement has been changed to ReDim Preserve to preserve the existing values in the array. The index used to assign the new value to the array has been changed to UBound(csa) instead of UBound(csa) + 1.
- In the Count property, the return value has been changed to UBound(csa) + 1 to return the correct count of items in the array.
Sure! Here’s an example use case for the CustomStrArray class:
Let’s say you’re building a program that needs to store a list of names. You could use the CustomStrArray class to create an array of strings that allows you to easily add and remove names, as well as get the count of names in the array.
Here’s some example code that uses the CustomStrArray class:
' Create a new instance of the CustomStrArray class
Dim names As New CustomStrArray
' Add some names to the array
names.Add "Alice"
names.Add "Bob"
names.Add "Charlie"
' Print the count of names in the array
Debug.Print "Number of names: " & names.Count
' Print each name in the array
Dim i As Long
For i = 0 To names.Count - 1
Debug.Print names(i)
Next i
' Remove a name from the array
names.Remove "Bob"
' Print the count of names in the array again
Debug.Print "Number of names: " & names.Count
This program creates a new instance of the CustomStrArray class, adds some names to the array, prints the count of names in the array, prints each name in the array, removes a name from the array, and then prints the count of names in the array again.
The CustomStrArray class makes it easy to manage the list of names, without having to worry about the underlying details of the array implementation.
Public Sub Remove(ByVal str As String)
Dim i As Long
For i = LBound(csa) To UBound(csa)
If csa(i) = str Then
' Shift elements after i one position to the left
Dim j As Long
For j = i To UBound(csa) - 1
csa(j) = csa(j + 1)
Next j
' Shrink the array by one element
ReDim Preserve csa(UBound(csa) - 1)
Exit For
End If
Next i
End Sub
The Remove method loops through the elements of the array and removes the first occurrence of the specified string. It does this by shifting all the elements after the removed element one position to the left, and then shrinking the array by one element.
With this updated implementation, you can now use the Remove method to remove elements from the CustomStrArray class. For example:
' Create a new instance of the CustomStrArray class
Dim names As New CustomStrArray
' Add some names to the array
names.Add "Alice"
names.Add "Bob"
names.Add "Charlie"
' Remove a name from the array
names.Remove "Bob"
' Print the count of names in the array
Debug.Print "Number of names: " & names.Count
' Print each name in the array
Dim i As Long
For i = 0 To names.Count - 1
Debug.Print names(i)
Next i
Sure, here’s the modified class code with the index starting at 1:
Class CustomStrArray
' Define the private variables
Private csa() As String
' Define the public properties
Public Property Get Count() As Long
Count = UBound(csa)
End Property
' Define the public methods
Public Sub Add(ByVal str As String)
ReDim Preserve csa(UBound(csa) + 1)
csa(UBound(csa)) = str
End Sub
Public Sub Remove(ByVal index As Long)
If index < 1 Or index > UBound(csa) Then
Err.Raise 9, , "Index out of range"
Exit Sub
End If
Dim i As Long
For i = index To UBound(csa) - 1
csa(i) = csa(i + 1)
Next i
ReDim Preserve csa(UBound(csa) - 1)
End Sub
Public Property Get Item(ByVal index As Long) As String
If index < 1 Or index > UBound(csa) Then
Err.Raise 9, , "Index out of range"
Else
Item = csa(index - 1)
End If
End Property
Public Property Let Item(ByVal index As Long, ByVal value As String)
If index < 1 Or index > UBound(csa) Then
Err.Raise 9, , "Index out of range"
Else
csa(index - 1) = value
End If
End Property
' Define the Class_Initialize event
Private Sub Class_Initialize()
' Do something when the class is initialized
ReDim csa(0)
End Sub
' Define the Class_Terminate event
Private Sub Class_Terminate()
ReDim csa(0)
End Sub
End Class
Note that the Item property and the Remove method have been modified to start indexing at 1.
Here’s an example of how to use the modified class with the index starting at 1:
' Create an instance of the CustomStrArray class
Dim arr As New CustomStrArray
' Add some elements to the array
arr.Add "apple"
arr.Add "banana"
arr.Add "cherry"
' Get the number of elements in the array
MsgBox "Count: " & arr.Count ' Output: Count: 3
' Get the second element of the array
MsgBox "Element 2: " & arr.Item(2) ' Output: Element 2: banana
' Change the value of the third element
arr.Item(3) = "date"
' Remove the first element
arr.Remove 1
' Get the new number of elements in the array
MsgBox "Count: " & arr.Count ' Output: Count: 2
' Get the first element of the array
MsgBox "Element 1: " & arr.Item(1) ' Output: Element 1: banana
Note that the Item property and the Remove method are now called with indices starting at 1.
The final CustomStrArray Class
Finally print everything again with the following changes:
- add the example at the end of the class,
- the remove member function should take a string as argument
Here’s the modified class code with the changes as requested:
Class CustomStrArray
' Define the private variables
Private csa() As String
' Define the public properties
Public Property Get Count() As Long
Count = UBound(csa)
End Property
' Define the public methods
Public Sub Add(ByVal str As String)
ReDim Preserve csa(UBound(csa) + 1)
csa(UBound(csa)) = str
End Sub
Public Sub Remove(ByVal str As String)
Dim i As Long
For i = 1 To UBound(csa)
If csa(i) = str Then
If i < UBound(csa) Then
csa(i) = csa(UBound(csa))
End If
ReDim Preserve csa(UBound(csa) - 1)
Exit For
End If
Next i
End Sub
' Define the Item property
Public Property Get Item(ByVal index As Long) As String
Item = csa(index)
End Property
Public Property Let Item(ByVal index As Long, ByVal value As String)
csa(index) = value
End Property
' Define the Class_Initialize event
Private Sub Class_Initialize()
' Do something when the class is initialized
ReDim csa(0)
End Sub
' Define the Class_Terminate event
Private Sub Class_Terminate()
ReDim csa(0)
End Sub
End Class
' Example usage of the CustomStrArray class
Dim arr As New CustomStrArray
arr.Add "apple"
arr.Add "banana"
arr.Add "cherry"
MsgBox "Count: " & arr.Count ' Output: Count: 3
arr.Item(2) = "orange"
MsgBox "Element 2: " & arr.Item(2) ' Output: Element 2: orange
arr.Remove "banana"
MsgBox "Count: " & arr.Count ' Output: Count: 2
MsgBox "Element 1: " & arr.Item(1) ' Output: Element 1: apple
Note that the Remove method now takes a string argument instead of an integer index and an example usage of the class has been added at the end of the code.
Possible to extend the class?
Certainly! Here’s an updated version of the class that can handle both strings and objects:
Class CustomArray
' Define the private variables
Private arr() As Variant
' Define the public properties
Public Property Get Count() As Long
Count = UBound(arr) - LBound(arr) + 1
End Property
' Define the public methods
Public Sub Add(ByVal element As Variant)
ReDim Preserve arr(LBound(arr) To UBound(arr) + 1)
arr(UBound(arr)) = element
End Sub
Public Sub Remove(ByVal element As Variant)
Dim i As Long
For i = LBound(arr) To UBound(arr)
If arr(i) = element Then
If i < UBound(arr) Then
arr(i) = arr(UBound(arr))
End If
ReDim Preserve arr(LBound(arr) To UBound(arr) - 1)
Exit For
End If
Next i
End Sub
' Define the Class_Initialize event
Private Sub Class_Initialize()
' Do something when the class is initialized
ReDim arr(1 To 0)
End Sub
' Define the Class_Terminate event
Private Sub Class_Terminate()
ReDim arr(1 To 0)
End Sub
End Class
And here’s an example usage:
Sub Example()
Dim myArray As New CustomArray
myArray.Add "Hello"
myArray.Add 123
Dim obj As New MyClass
myArray.Add obj
Debug.Print "Count: " & myArray.Count ' Prints "Count: 3"
myArray.Remove "Hello"
Debug.Print "Count: " & myArray.Count ' Prints "Count: 2"
End Sub
Class MyClass
' Define the properties and methods of MyClass
End Class
If you want to add an object to the array, you can simply assign the object to the array element. In this case, you don’t need to use the Set keyword.
For example, consider the following modified Add method of the CustomVariantArray class:
Public Sub Add(ByVal var As Variant)
If IsObject(var) Then
ReDim Preserve cva(LBound(cva) To UBound(cva) + 1)
Set cva(UBound(cva)) = var
Else
ReDim Preserve cva(LBound(cva) To UBound(cva) + 1)
cva(UBound(cva)) = var
End If
End Sub
Here, the IsObject function is used to check whether the variant is an object or not. If the variant is an object, we use the Set keyword to assign the object to the array element. If the variant is not an object, we simply assign the value to the array element without using the Set keyword.
Note that when assigning an object to a variable or an array element, you must use the Set keyword to set the reference to the object.
I apologize for any confusion caused by my previous answer. To clarify, when adding an object to an array, you do not need to use the Set keyword to assign the object to the array element. Instead, you can simply assign the object to the array element.
In VBA, the Set keyword is used to assign an object reference to an object variable, not to an array element. When you assign an object to an array element, VBA automatically assigns a reference to the object, so you do not need to use the Set keyword in this case.
Thank you for bringing this to my attention, and I hope this clears up any confusion.
If so it would be save to use for example TypeName(var(2)) …
Yes, that’s correct. In VBA, you can use both Set cva(UBound(cva)) = var and cva(UBound(cva)) = var to assign objects to an array element. And you can use TypeName(var) to get the type name of the object in the array. However, if the array element contains a string, then you don’t need to use Set to assign the value, you can simply use cva(UBound(cva)) = var as you would for a non-object variable.
The drawback with ChatGPT AI as far as I see: as long as you ask the right questions, you get pretty good answers. However, to ask the right questions you need to know the programing language already.
When digging deeper into a detail, sometimes the answer is not consistent all the time. See last questions about the need to use the set keyword for an array or not.