this
this

Reputation: 1426

Why are missing `Set` for certain types a runtime error rather than compile error?

Given the following VBA code, assuming that a Something is just a VBA class module....

Public Type Foo
    SomeThing As Something
End Type

Public Sub TestFoo()
    Dim x As Foo
    With x
        'Correct way to do it
        Set .someThing = New Something
    End With

    With x
        'This is wrong but realized only as a RTE 
        '438: Object doesn't support this property or method
        .SomeThing = New Something
    End With
End Sub

In contrast, if you change the type to something like VBA.Collection as below:

Public Type Foo
    SomeThing As VBA.Collection
End Type

Public Sub TestFoo()
    Dim x As Foo

    With x
        .SomeThing = New VBA.Collection
    End With
End Sub

This is now a compile error, with Argument Not Optional. This is obviously wrong but why is it a compile-time error only with VBA.Collection?

Upvotes: 3

Views: 42

Answers (2)

Comintern
Comintern

Reputation: 22195

This is explained in the VBA Language Specification. The semantics of the assignment inside the With block is driven by whether or not the statement is a Set statement or a Let statement. In this context, it is a Let statement:

With x
    .SomeThing = New Something
End With

Note that in the VBA grammar, the keyword Let is optional (obsolete):

let-statement = ["Let"] l-expression "=" expression

In a Set statement, the Set keyword is required:

set-statement = "Set" l-expression "=" expression

Inside of a With block, the l-expression is basically the UDT member, although the exact same behavior applies if x is used directly.

When evaluating a Let expression, the semantics are described in section 5.4.3.8:

Static Semantics.

This statement is invalid if any of the following is true:

  • <expression> cannot be evaluated to a simple data value (section 5.6.2.2 ).

Following that to 5.6.2.2 (Evaluation to a simple data value), the following runtime semantics apply (applicable rule only):

Runtime semantics.

At runtime, the simple data value’s value and value type are determined based on the classification of the expression, as follows:

  • If the expression’s value type is a specific class:

    • If the source object has a public default Property Get or a public default function, and this default member’s parameter list is compatible with an argument list containing 0 parameters, the simple data value’s value is the result of evaluating this default member as a simple data value.

    • Otherwise, if the source object does not have a public default Property Get or a public default function, runtime error 438 (Object doesn’t support this property or method) is raised.

Thus the runtime error 438 for SomeThing As Something.

With the Collection, the Let static semantics still apply, but it fails the static semantics of 5.6.2.2 (which gives the compile error). Again, the preceding inapplicable semantics are omitted:

Static semantics. The following types of expressions can be evaluated to produce a simple data value:

  • An expression classified as a value expression may be evaluated as a simple data value based on the following rules:

    • If the declared type of the expression is a specific class:

    • If this class has a public default Property Get or function and this default member’s parameter list is compatible with an argument list containing 0 parameters, simple data value evaluation restarts as if this default member was the expression.

The default member of Collection is a function (.Item) that takes a single parameter Index. In this code, the parameter is not provided, so the argument list is incompatible:

With x
    .SomeThing = New VBA.Collection
End With

Thus the Argument Not Optional compile error.

Upvotes: 3

this
this

Reputation: 1426

In typing up the question, it struck me that the VBA.Collection had a default member. Thus, the compiler was interpreting the .Something = New VBA.Collection as an assignment to the default member... except that the Item is an indexed property. That explains why we get Argument not optional which would be quite a strange error to get with a Set statement.

In contrast, a VBA class module might not have a default member at all, so that there is no indexed property + default member to trigger a compile-time error. However, it also means that the bad syntax won't be caught until runtime.

Upvotes: 1

Related Questions