I am working an a more meaningful way to print objects in VBA. The desired result should look something like this.
Console.PrintLine List.Create(1, 2, 3)List(1, 2, 3)The concept is that objects implementing anIPrintable interface are printed as theirToString property. Primitive data types are printed as is
Console.PrintLine "a"aAnd other objects are represented as "TypeName(&ObjPtr)"
Console.PrintLine New CollectionCollection(&150653720)But the issue that is gunking up my design is that I want nested objects to represent themselves
Console.PrintLine List.Create(1, List.Create(), New Collection)List(1, List(), Collection(&150653384))My solution is to use an auxiliary helper methods, located in a standard module calledcast, which in a way provides a default implementation ofIPrintable
Public Function ToString(ByVal x As Variant) As String Dim result As String If TypeOf x Is IPrintable Then result = x.ToString ElseIf IsObject(x) Then result = DefaultObjectToString(x) Else result = CStr(x) End If ToString = resultEnd FunctionPrivate Function DefaultObjectToString(ByVal x As Object) As String DefaultObjectToString = ObjectToString(x, cast.CArray(Array("&" & ObjPtr(x))))End FunctionPublic Function ObjectToString(ByVal o As Object, ByRef members() As Variant, _ Optional ByVal delim As String = ", ") As String Dim stringMembers() As String If LBound(members) <= UBound(members) Then ReDim stringMembers(LBound(members) To UBound(members)) End If Dim i As Long For i = LBound(members) To UBound(members) stringMembers(i) = ToString(members(i)) Next i ObjectToString = TypeName(o) & "(" & Join(stringMembers, delim) & ")"End FunctionI would want this to be located in theIPrintable class but that must be empty to use it as an interface.
Now any method that is printing the objects can just usecast.ToString like console does
Public Sub PrintLine(Optional ByVal x As Variant) If IsMissing(x) Then Debug.Print vbNullString Else Debug.Print cast.ToString(x) End IfEnd SubAlso here is howList implementsIPrintable (ToArray is just an array version of the list.)
Public Property Get ToString(Optional delim As String = ", ") As String ToString = cast.ObjectToString(Me, ToArray, delim)End PropertyPublic Property Get IPrintable_ToString() As String IPrintable_ToString = ToString()End PropertyIf I had a BinaryTree object it would look like this.
Public Property Get ToString() As String ToString = cast.ObjectToString(Me, Array(LeftTree, RightTree), ", ")End Property- \$\begingroup\$Sorry it's taken me a while to look at this. Can you elaborate on why you want
Castto be a class?\$\endgroup\$RubberDuck– RubberDuck2015-02-04 02:01:35 +00:00CommentedFeb 4, 2015 at 2:01 - \$\begingroup\$
castis a standard module not a class. I will update the post to specify\$\endgroup\$cheezsteak– cheezsteak2015-02-04 14:48:30 +00:00CommentedFeb 4, 2015 at 14:48 - \$\begingroup\$Right. I get that, but I don't understand why exactly you need it to be a class. It seems an appropriate use for a module.\$\endgroup\$RubberDuck– RubberDuck2015-02-04 14:51:29 +00:00CommentedFeb 4, 2015 at 14:51
- 1\$\begingroup\$@RubberDuck There really isn't an appropriate place for it. It really should be in IPrintable as a default implementation, but those don't exist in VBA. Making it a static class implies that I should be able to pass it as an argument but idk if that should be allowed or not.\$\endgroup\$cheezsteak– cheezsteak2015-02-04 15:17:16 +00:00CommentedFeb 4, 2015 at 15:17
- 2\$\begingroup\$I'd love to see this
Castmodule!\$\endgroup\$Mathieu Guindon– Mathieu Guindon2015-02-04 15:20:29 +00:00CommentedFeb 4, 2015 at 15:20
1 Answer1
I don't see anything ugly about yourCast module. If it was .Net I would use aStatic (Shared) type class, and a standard *.bas module is roughly equivalent in VB6. It seems to have been the right move to me.
What I do question is the usefulness of defaulting to the object's pointer as a string representation of it. Since VB6 supports default properties, I would take advantage of it. It's not exactly pretty, but perhaps a more useful representation of an object.
Private Function TryCastToString(x As Variant) As String On Error GoTo ErrHandler TryCastToString = CStr(x) Exit FunctionErrHandler: Const MethodNotSupportedError As Integer = 438 If Err.Number = MethodNotSupportedError Then TryCastToString = "&" & ObjPtr(x) Else Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext End IfEnd FunctionWhich would change this function:
Private Function DefaultObjectToString(ByVal x As Object) As String DefaultObjectToString = ObjectToString(x, cast.CArray(Array("&" & ObjPtr(x))))End Function
Into this:
Private Function DefaultObjectToString(ByVal x As Object) As String DefaultObjectToString = ObjectToString(x, cast.CArray(Array(TryCastToString(x))))End FunctionThis provides a much nicer string back. Consider a workbook with a value of "Hello!" in cell A1 and the following code.
Public Sub test() Debug.Print Cast.ToString(ThisWorkbook) Debug.Print Cast.ToString(Range("A1"))End SubThis would result in the following:
Workbook(&2349672)Range(Hello!)
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.

