Reputation: 1426
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
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
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