VBA compile-time type checking does not include classes?

Y

Yarik

Hi,

Now I am really perplexed: it looks like MS Access doesn't distinguish
classes when doing compile-time type checking...

For example, a code fragment like this

Public Sub DoSomethingWithForm(frm as Form)
End Sub

Public Sub Nuisance()
Call DoSomethingWithForm(CurrentProject.Connection)
End Sub

merrily compiles without a hitch. (In Visual Basic it would produce a
compile-time "Type mismatch" error.)

Is this a feature of MS Access VBA (or VBA in general)? Or is this a
bug? Or is this one of the possible two options??

Thank you,
Yarik.
 
A

Albert D. Kallal

Is this a feature of MS Access VBA (or VBA in general)? Or is this a
bug? Or is this one of the possible two options??

Well, I think more of a issue that if you pass a "object", then it is
allowed:


dim f as string
dim g as object

Call DoSomethingWithForm(f)

The above "f" is a defined string type, and is NOT allowed

however

Call DoSomethingWithForm(g)

the above *is* allowed. So, I think the problem in this case is that
currentproject is of a data type "object", and thus is only determined at
runtime, and NOT compile time. I think the results would be the same in
vb.......(ie: pass a object type is allowed - and is NOT determined at
compile time).
 
V

Van T. Dinh

IIRC, I think someone previously stated that when you declare an object in
the Sub argument, VBA simply looks for the handle to the object and thus
during compilation, VBA sees the declaration requires a handle and the
calling code supplies the handle and thus, it is good enough for VBA to
compile ...

My 2 cents worth of recollection ...
 
T

Terry Kreft

That's not true, neither VB nor VBA do type checking at compile time.

The code you qoute would generate a run time error (13: Type Mismatch) and
even then only because the object passed has been instantiated.

The following code, for example:-

Public Sub DoSomethingWithForm(frm As Form)
End Sub

Public Sub Nuisance()
Dim a As ADODB.Connection
Call DoSomethingWithForm(a)
End Sub

Would not produce a compile time or a runtime error, whereas changing it to
this:-

Public Sub DoSomethingWithForm(frm As Form)
End Sub

Public Sub Nuisance()
Dim a As ADODB.Connection
Set a = New ADODB.Connection
Call DoSomethingWithForm(a)
End Sub

Will produce a run-time error (13).
 
T

Terry Kreft

Yarik is wrong in what he says (VB and VBA handle this the same way), but to
follow up on what you are saying.

It would be very intensive for VB(A) to do anything else as it would have to
check all the interfaces of the object you are passing to see if the object
can be cast to the interface that the receiving procedure is expecting; to
then have to do that for every single object argument in every single call
for every single procedure which accepts an object argument would be
massive.

What they sensibly (IMO) did instead was opt for a run time error being
generated.
 
T

Terry Kreft

Oh I forgot one (at first sight) interesting quirk of this checking only at
runtime

If we change the code to this (simply so we can instantiate a new object in
DoSomething):-

Public Sub DoSomethingWithForm(cmd As ADODB.Command)
Set cmd = New Command
End Sub

Public Sub Nuisance()
Dim a As ADODB.Connection
Call DoSomethingWithForm(a)
End Sub

We still get a runtime error 13, but instead of it being in the call to
DoSomething it's on the return. Which is obvious when you think about it but
can be very confusing when you are trying to debug.

Whereas this
Public Sub DoSomethingWithForm(ByVal cmd As ADODB.Command)
Set cmd = New Command
End Sub

Public Sub Nuisance()
Dim a As ADODB.Connection
Call DoSomethingWithForm(a)
End Sub

Doen't give a run-time error at all.
 
D

David W. Fenton

Well, I think more of a issue that if you pass a "object", then it
is allowed:


dim f as string
dim g as object

Call DoSomethingWithForm(f)

The above "f" is a defined string type, and is NOT allowed

however

Call DoSomethingWithForm(g)

the above *is* allowed. So, I think the problem in this case is
that currentproject is of a data type "object", and thus is only
determined at runtime, and NOT compile time. I think the results
would be the same in vb.......(ie: pass a object type is allowed -
and is NOT determined at compile time).

I have a strong suspicion that this is caused by implicit coercion.
You can assign the value returned from CurrentProject.Connection to
variables of String type, of Object type of Access.Connection type
and of ADODB.Connection type.

In a sense, one has to think that in VBA context,
CurrentProject.Connection returns the equivalent of a variant. Thus,
there's no possibility of type checking.

And, I suspect, there's no type checking except with a variable
declaration (which can't be coerced when passed ByRef -- possibly
will coerce when passed ByVal, but I haven't tested it).

Implicit coercion is bad, and this is an example of why.
 
T

Terry Kreft

You can assign CurrentProject.Connection to string variables because the
default property is the ConnectionString which is of type string.
i.e.
dim s as string
s = CurrentProject.Connection

is functionally the same as
dim s as string
s = CurrentProject.Connection.ConnectionString

You can assign it to a variable of type object because a variable of type
object can hold any other COM object and as CurrentProject.Connection is of
type Connection you can, of course, assign it to a variable of type
connection.
 
A

Albert D. Kallal

Do note in my example in eh case of a defined variable (non object type),
then correct "type" checking DOES occur at compile time.....
 
T

Terry Kreft

Yes, because this check is relatively trivial compared to checking for all
the possible interface casts.
 
D

David W. Fenton

You can assign CurrentProject.Connection to string variables
because the default property is the ConnectionString which is of
type string. i.e.
dim s as string
s = CurrentProject.Connection

is functionally the same as
dim s as string
s = CurrentProject.Connection.ConnectionString

You can assign it to a variable of type object because a variable
of type object can hold any other COM object and as
CurrentProject.Connection is of type Connection you can, of
course, assign it to a variable of type connection.

Er, that doesn't seem to explain it, as something has to coerce the
default value, doesn't it? That is, if the default value is a
string, then how does it get converted to a COM object?

There has to be coercion involved somewhere for an identical
property to return a value that is assignable to variables of two
radically different types.
 
Y

Yarik

Terry said:
Yarik is wrong in what he says (VB and VBA handle this the same way), but to
follow up on what you are saying.

You are right. Apparently, when I was doing my quick experiment, I
mistaken VB's run-time diagnostics for compile-time one. I guess, on
modern computers, it compiles and runs too fast. :)))
It would be very intensive for VB(A) to do anything else as it would have to
check all the interfaces of the object you are passing to see if the object
can be cast to the interface that the receiving procedure is expecting; to
then have to do that for every single object argument in every single call
for every single procedure which accepts an object argument would be
massive.

What they sensibly (IMO) did instead was opt for a run time error being
generated.

Hmm... I am not sure I can agree wish such justification. If type
checking is so expensive, then it only seems more reasonable to do it
at compile-time, not at run-time. I believe the main reason behind this
was just to save money on developing a decent compiler...

BTW, why comparing classes for "compatibility" would be so much more
expensive than comparing primitive types? I am far from being an expert
in compilers' internal intricacies, but even if we take into account
possible subclassing, comparing of classes should not be terribly
expensive. Or should it?

Also why on Earth compile-time checking of primitive types (at least
some help from the compiler) is suppressed when parameters are being
passed by value? Wasn't availability of Variant type enough to enable
"loosely-typed" programming style??

Anyway, the questions above are rather rhetorical - MS is abandoning
VB6 (at last!!!), so there is no much sense to rant about shortcomings
of this tool.

Thank you!
Yarik.
 
T

Terry Kreft

Have a look in the registry, look in the HKEY_CLASSES_ROOT/CLSID for an idea
of the potential number of items that would have to be checked for each
call. Consider how long that would take at compile time.

If you are using a component written in C then you can have a large number
of inherited classes all of which may be presented as an interface which
would need checking for.

MS abandoning VB6 is not something to rejoice over (IMO).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top