I have the following VBA code.
Option Explicit
Sub problem1()
Dim speedmph As Double, speedkph As Double, speedfts As Double
speedmph = Val(InputBox("Enter a speed (mph)"))
Call convert(speedmph, speedkph, speedfts)
MsgBox "The speed is " & speedkph & " km/hr and " & speedfts & "ft/s."
End Sub
Sub convert(speedmph, speedkph, speedfts)
speedkph = speedmph * 1.609
speedfts = speedmph * 1.467
End Sub
I've noticed that when I called the convert procedure as it is shown above, it worked.
But if I tried to insert a value for speedkph (e.g. 0), the convert
procedure does not override that and MsgBox prints out 0 for speedkph.
Why doesn't convert
override the 0
even though it forces
the variable to change in its function definition?
Regarding scope, the parameters for a Function
or Sub
only have scope within the Function
or Sub
that they are declared in. The same thing holds true for variables declared with the keyword Dim
(or ReDim
for arrays). For undeclared variables, the scope is the next highest scope if a matching identifier exists (module level private variables, then global variables). If no identifier with a greater scope exists, it is implicitly declared as a Variant
in local scope. So, in this line...
Sub convert(speedmph, speedkph, speedfts)
...the parameters speedmph
, speedkph
, and speedfts
are all local to Sub convert
(and are implicitly Variant
because there aren't As
statements), and in this line...
Dim speedmph As Double, speedkph As Double, speedfts As Double
...the parameters speedmph
, speedkph
, and speedfts
are all local to Sub problem1()
.
That out of the way, let's address why your MsgBox
shows anything at all. The default method of passing parameters is ByRef
, so if you were to actually specify all of the implicit parts of your Sub
declaration, it would look like this:
Public Sub convert(ByRef speedmph As Variant, ByRef speedkph As Variant, _
ByRef speedfts As Variant)
When you call it like this...
Call convert(speedmph, speedkph, speedfts)
...you pass it references to the local variables speedmph
, speedkph
, speedfts
you declared in Sub problem1()
. The Sub convert
assigns values to those references, but each procedure only holds it's own copy of the reference in local scope. The identifiers are completely irrelevant at this point. In fact, this works exactly the same as your sample code (only the identifiers have been changed):
Sub problem1()
Dim speedmph As Double, speedkph As Double, speedfts As Double
speedmph = Val(InputBox("Enter a speed (mph)"))
Call convert(speedmph, speedkph, speedfts)
MsgBox "The speed is " & speedkph & " km/hr and " & speedfts & "ft/s."
End Sub
Sub convert(foo, bar, baz)
bar = foo * 1.609
baz = foo * 1.467
End Sub
Now to answer your specific question, the reason you can't use a "placeholder" value of 0
is that 0
isn't a variable - it's a literal. When it's passed to Sub convert
, the only place the reference exists is as a variable on the call stack - Sub problem1()
doesn't hold a reference to it, so there's no way for Sub problem1()
to tell what Sub convert
does with it. The stack variable is destroyed when Sub convert
returns and the call stack unwinds. Basically, passing a literal to a ByRef
parameter is functionally equivalent to passing it ByVal
.