Hi Dick,
By definition, late binding in VO (so also in x#, if you ignore the Dynamic type for now) is code that uses USUALs; in other words not strongly typed vars, exports, return types etc. Whenever you use a USUAL to do any calculation or when you call a method on a USUAL, the compiler does not know what the USUAL will contain when the code will execute, so it generates generalized code for that, with no compile time checking. This is what's late binding, in very short and without using really official terminology
.
So no matter the compiler, when you use USUALs, no compiler knows what the usual will hold at runtime, so it always creates late bound code. In order to get rid of late binding, you need to get rid of the USUALs, mainly when you call methods/properties etc on USUAL vars. Of course this is not always easy, because some of those USUALs are declared in the SDK, so you'd need to modify the SDK code for that.
Alternatively, you can use an intermediate option, to use intermediate strongly typed vars, instead of operating on the untyped vars of the SDK or of your own code. For example, the code
is late bound, because "Server" is a USUAL ACCESS of the Window class. But you could rewrite it like that:
Code: Select all
LOCAL oServer AS DbServer
oServer := SELF:Server
oServer:GoTop()
which is a lot more "safe" and efficient that the previous code. It is still not perfectly safe, because it is not guaranteed that at runtime "SELF:Server" will indeed contain a var of type DBServer, so the assignment could potentially fail at runtime if "SELF:Server" happens to contain an instance of a class not inheriting from DBServer. But from experience we do know that "Server" will indeed hold a DBServer object, so it should work fine.
Then, the 2nd line is pure early bound code, which is efficient and type safe now, you cannot call a method that does not exist this way anymore. Furthermore, with this version of the code you will get help from intellisense with member completion, something you were obviously not getting with the early bound version. An alternative syntax for the above would be to use a cast in a single line:
or
Code: Select all
(SELF:Server ASTYPE DbServer):GoTop()
but the 3-line version is probably more readable.
Chris