views:

267

answers:

1

Visual Basic has default properties that are sometimes implicitly called when evaluating an expression. However, I seem to of come across a discrepancy with this implicit execution of default properties. The project layout looks like:

Class1:

property test -> class2 (default)

Class2:

property test -> string "hello world" (default)

Form1:

Dim x As New Class2
MsgBox x
Debug.Print x

The MsgBox statement will implicitly call x's default (being test on class1) and further more it will call the default on that (being test on class2) which results in "hello world" being displayed on the screen. The Debug.Print statement does not do this however, and by following the debugger, it can be seen that only the first default (on class1) is being called.

I have verified that many of the built in functions such as MsgBox/RTrim/LTrim exhibit this behaviour, and that any self written methods or class methods do not do this; but am unable to work out why this occurs?

+4  A: 

This is not a "behaviour" of the built-in functions at all, but depends on the way COM does converting object references and variants to strings. This also has a connection with Set and Let language keywords and expression evaluation, especially parentheses. Consider this sample code:

Private Sub Form_Load()
    Dim x As Class1
    Dim v As Variant
    Dim s As String

    Set x = New Class1
    Set v = x   ' None
    Let v = x   ' Once
    Set v = (x) ' Once
    Let v = (x) ' Twice
    's = x      ' Compile error: Type mismatch
    Set v = x
    s = v       ' Twice
    s = CVar(x) ' Twice
    MsgBox x
    'Debug.Print CStr(x) ' Compile error: Type mismatch
    'Debug.Print CVar(x) ' Run-time error: Type mismatch
    Debug.Print CStr(CVar(x)) ' Twice
    pvTest1 x
End Sub

Private Function pvTest1(ByVal o As Variant)
    'Debug.Print o      ' Run-time error: Type mismatch
    Debug.Print CStr(o) ' Twice
End Function

Notice how casting object reference to a string is a compile-time error (the CStr(x) call) while a variant containing a reference (an IDispatch one) is cast just fine (s = v). This last assignment will "unfold" default properties as deep as it takes while the default propery evaluates to an IDispatch (calling Invoke with DISPID set to -1).

In short: if you have a reference to an object and need to evaluate default properties recusively to a value of "primitive" data type (e.g. string) use CStr(CVar(x)) (or CInt(CVar...), etc)

wqw