xsharp.eu • Xported project: Error XS1061 'type' does not contain a definition for .. - Page 2
Page 2 of 2

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Wed Sep 05, 2018 1:45 pm
by wriedmann
Hi Dick,
So good to know that I didn't miss something obvious and late binding is a normal practice. I assume this can be abandoned as soon as we have the Core X#.
It depends on your programming style, it has nothing to do with the X# runtime.

First of all, all access/assign variables should be typed. This will solve a lot of late binding (and I'm doing this already in VO whenever possible to be prepared for the X# move).

But there are many cases where late binding permits more elegant code - to make it without you would need to use interfaces.

Wolfgang

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Wed Sep 05, 2018 9:30 pm
by ic2
Hello Wolfgang, Karl,

I still don't understand why the code above (with my subclass to dbserver) works without late binding or compiler errors. It has nothing else than the few not-strong-typed code I wrote. Also I don't understand why it's impossible that, on rewriting the code to a Core X# version, the init can not be made strong typed. But after all I am not a compiler builder ;)

Most intriguing for now is: what do I need to do if I want code like SELF:Server:Close() work without Late Binding? I mean: how can I solve that with access/assign variables? That's the majority of the 375 errors. Or can't I prevent these?

Dick

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Wed Sep 05, 2018 10:21 pm
by Chris
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

Code: Select all

SELF:Server:GoTop()
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:

Code: Select all

((DbServer)SELF:Server):GoTop()
or

Code: Select all

(SELF:Server ASTYPE DbServer):GoTop()
but the 3-line version is probably more readable.

Chris

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Thu Sep 06, 2018 7:04 am
by robert
Chris,

Internally the variable is a DataServer:

PROTECT oAttachedServer AS DataServer

So this should always work (except when SELF:Server is a NULL_OBJECT)

LOCAL oServer AS DataServer
oServer := SELF:Server
oServer:GoTop()

Of course this does not allow you to call methods that are DbServer specific, like SetOrder().

Robert

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Thu Sep 06, 2018 10:36 am
by Chris
Robert,

Agreed, but that's a library implementation detail that we must somehow know about, that's why I said "we know from experience". My point was that when we use an intermediate var for a USUAL, or use a cast on it, we do improve things a lot, but still in general this "unsafeness" of converting the USUAL (so unknown type at compile time) to a strong typed var still exists. Complete solution and only way to enforce full compile time checking is to strongly type the ACCESS.

Chris

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Thu Sep 06, 2018 11:04 am
by ic2
Hello Robert, Chris,
LOCAL oServer AS DbServer
oServer := SELF:Server
oServer:GoTop()
Thanks for all the explanations. The above is what I basically do in the non late bound X# program. Sounds to me like a good solution to prevent late bound code.

Dick

Xported project: Error XS1061 'type' does not contain a definition for ..

Posted: Thu Sep 06, 2018 7:21 pm
by wriedmann
Hi Dick,

exactly that is what I'm doing every time I touch VO code. And I don't use the generic server class, but the one that is used in this window, like this:

Code: Select all

local oOrder as Order

oOrder := self:Server
....(method calls)....
But there are other places where compile time binding has a big performance advantage: in event handlers.
There I'm writing code like this:

Code: Select all

method Dispatch( oEv ) class EnhancedSLE
local oEvent as @@Event 
oEvent := oEv
.....
Wolfgang