My class has multiple methods. Some methods take parameters. Those methods require the keyword "Call" to work. Why?
MyObject.MyMethod 'Works just fine without Call.
Call MyObject.MyMethod(arg1, arg2) 'Requires Call. Won't compile without it.
Call
is never required. In fact it's been obsolete since the advent of implicit call syntax in... Visual Basic 4.0, if I recall correctly.
object.MemberName arg1, arg2
Notice the parentheses are gone. This would be illegal, as you noted:
object.MemberName (arg1, arg2)
Notice the whitespace between MemberName
and the opening (
: the VBE will always put a space there. That's the VBE saying "Ok so I'll take what's in these parentheses, evaluate that as an expression, and pass the result by value (regardless of the member's signature specifying ByRef
, explicitly or not) to the member you're invoking". Except (foo, bar)
isn't a legal expression, so the code doesn't compile.
When MemberName
returns a value that the caller needs to capture, the parentheses behave differently:
foo = object.MemberName(arg1, arg2)
Notice there's no whitespace anymore; the VBE will remove it if you add any.
So with a more familiar and concrete example - note that it has nothing to do with objects & members:
MsgBox "Yes?", vbYesNo ' works fine
Call MsgBox("Yes?", vbYesNo) ' works fine
Call VBA.Interaction.MsgBox("Yes?", vbYesNo) ' works fine
MsgBox ("Yes?", vbYesNo) ' illegal
result = VBA.Interaction.MsgBox("Yes?", vbYesNo) ' works fine
The Call
keyword only exists in VBA6/VBA7 for backward-compatibility purposes, like many, many other language constructs (While...Wend
comes to mind). That's why Rubberduck (disclaimer: I'm one of the admins of that open-source project) flags its use as "obsolete", and provides tooling to remove it.
@MathieuGuindon's answer covers the how part really well, so I thought I'd tackle the "why" part.
VB's syntax overloads the parentheses as a syntactical element. In the case of a procedure call, they are used to surround the argument list:
argument-list = [positional-or-named-argument-list] positional-or-named-argument-list = *(positional-argument ",") required-positional-argument positional-or-named-argument-list =/ *(positional-argument ",") named-argument-list named-argument-list = named-argument *("," named-argument)
Note that definition for an Argument List (5.6.13.1) falls under the category of Index Expressions (5.6.13), and this isn't simply a misnomer, because the parser has to statically determine what is being indexed. This is complicated by the fact that ()
is also used for array indexing, and indexed member indexing.
The Call
statement itself (5.4.2.1) consumes an argument list, but the fact that the parentheses can also be used as an indexer for a variable (arrays, etc.) means that there is the possibility that the expression to the right of Call
can be ambiguous without the following rule:
- If the Call keyword is specified:
- If a <call-statement> element’s referenced expression is an <index-expression>, the specified argument list is this expression’s argument list.
- Otherwise, the specified argument list is an empty argument list.
Forcing the use of the parentheses eliminates this ambiguity. One example would be something like this:
Sub Foo()
Dim Bar As Object
Call Bar 1 '<-- What is Bar here? Is this the default member of the object, or the Sub?
Bar 1 '<-- This in unambiguous, because ( ) are required to use a default member indexer.
End Sub
Sub Bar(paramater As Integer)
'Do something
End Sub
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With