Wednesday, March 08, 2006
Excelagility - Part II - Printing out objects with external polymorphism
Where we explore how to get rid of some of the verbose bureaucracy of VBA and how to create uniformity using 'Verbs' and external polymorphism..
Excelagility
- or -
How to Shape Excel with VBA into a Legible Expressive Agile Platform
~
V. 0.0.2
Printing Out Objects
Now we have objects, but it's not easy to print them out to screen, for example for debugging purposes.
We can do this by providing each class which is of interest to us with a method that converts it to string: a 'toString' method.
Dim a_person As Person
Set a_person = Person("John","Smith",#23/11/1980#)
Debug.Print a_person.toString
Let's add such a method to the 'Person' class:
Function toString() As String
toString = "Person(" & _
Me.Name & ", " & _
Me.Surname & ", " & _
Me.DateOfBirth & ") "
End Function
Now you can easily print out a Person object to the Immediate Window.
However, having to write 'Debug.Print' and 'toString' is quite verbose and we can devise a way to make this more readable.
Sub puts(an_entity)
Debug.Print strize(an_entity)
End Sub
The new 'puts' command substitutes the lengthy 'Debug.Print' command and it also forces the argument passed to it to be converted to a string. The actual conversion is performed by the 'strize' (short for string-ize) function.
The code for the 'strize' function employs a technique that I call 'external polymorphism' to handle entities of any type and not only Objects.
Function strize(an_entity) As String
If IsObject(an_entity) Then
strize = an_entity.toString
Else
strize = CStr(an_entity)
End If
End Function
This code now allows you to write much more expressive statements:
Dim a_person As Person
Set a_person = Person("John","Smith",#23/11/1980#)
puts a_person
puts a_person.DateOfBirth
puts a_person.Name
The 'puts' command, however, is not as robust as we would like it to be. If you pass it an object that does not implement the 'toString' method, then it will fail without providing much of an explanation. We can make it more robust by adding some simple error handling:
Function strize(an_entity) As String
On Error Goto cannot_convert_to_string
If IsObject(an_entity) Then
strize = an_entity.toString
Else
strize = CStr(an_entity)
End If
Exit Function
cannot_convert_to_string:
strize = TypeName(an_entity)
End Function
If the entity passed cannot be converted to string, then we recover by returning simply the type name of the entity. Alternatively we may want it to return an error message, using the 'MsgBox' command.