xsharp.eu • PARTIAL CLASS
Page 1 of 1

PARTIAL CLASS

Posted: Tue Feb 28, 2023 11:47 am
by stefan.ungemach
I'm struggling with XS0433 ("The type XX exists in both...") probably because I got something wrong with partial classes. The funny thing is that it did compile until 2 days ago...

Project 0:
CLASS dbAbstract inherit dbServer
...
END CLASS

Project 1 (including 0):
PARTIAL CLASS dbTABELLE inherit dbAbstract
(some generic ACCESSes which are not in dbAbstract)
END CLASS

Project 2 (including 0 and 1):
PARTIAL CLASS dbTABELLE inherit dbAbstract
(some overwritten methods which are also in dbAbstract)
END CLASS

In Project 3 I have:
function Start()
local TABELLE as dbTABELLE
(...)
Return

This suddenly tells me that the Type 'dbTABELLE' exists in both (1) and (2). What can cause this problem? Did I get the idea of partial classes wrong?

Note: if there are only some overwritten ACCESSes in the dbTABELLE block of (2) the error doesn't show up.

PARTIAL CLASS

Posted: Tue Feb 28, 2023 12:11 pm
by robert
Stefan,
Partial classes have to be in the same assembly (project) to be merged by the compiler.

Robert

PARTIAL CLASS

Posted: Tue Feb 28, 2023 12:17 pm
by stefan.ungemach
Hi Robert,

then I have an architectural problem.

In VO we have that base class dbAbstract. The subclasses are generated code into a library on top of that. Then these subclasses are extended in several layers above by the developers. Because under VO strongly typed stuff needs to be in the same module as the class declaration it belongs to everything we extend in this way further above needs to stay late bound.

I was hoping to improve our X# code in terms of strongly typing everything. Since it is unavoidable to spread code over several libraries (aka projects): What would be the best practise here?

PARTIAL CLASS

Posted: Tue Feb 28, 2023 12:55 pm
by robert
Stefan,
StefanUngemach post=25430 userid=7039 wrote: then I have an architectural problem.

In VO we have that base class dbAbstract. The subclasses are generated code into a library on top of that. Then these subclasses are extended in several layers above by the developers. Because under VO strongly typed stuff needs to be in the same module as the class declaration it belongs to everything we extend in this way further above needs to stay late bound.

I was hoping to improve our X# code in terms of strongly typing everything. Since it is unavoidable to spread code over several libraries (aka projects): What would be the best practise here?
VO was very flexible, allowing you to build constructs like this, that violated all normal design rules.
You could also add methods in a class hierarchy that was not yours (like inside GUI classes) between a grandparent and a grandchild, at the parent level.
It also allowed you to bypass calls in a hierarchy by calling methods in the class hierarchy, bypassing the super layer.
For security reasons, this is not allowed in .Net.

The only thing that I can think of right now is to implement some of these classes as ABSTRACT class, which forces the developers to implement the ABSTRACT methods in their code. You can still call the methods in the base library (because the signature is declared) but they have to be implemented in the subclasses that the developers write.

Robert

PARTIAL CLASS

Posted: Tue Feb 28, 2023 2:37 pm
by stefan.ungemach
My proplem is that we have approx. 1.500 tables. Most of them use the standard methods, but some (or groups of some) overwrite these for some quiete complex mechanisms. I cannot force the developers to overwrite the same method for hundreds of classes (which I'd need if I made the base class ABSTRACT). Plus, there is code which can only be overwritten at a higher level (when additional libraries have been linked in), and that happens on several layers.

Are there perhaps other options (like doing something with Interfaces or delegates)?

PARTIAL CLASS

Posted: Tue Feb 28, 2023 2:43 pm
by robert
Stefan,
Most likely, there are other ways to do this.
But I would need to see the design to give a meaningful advise

Robert

PARTIAL CLASS

Posted: Tue Feb 28, 2023 4:34 pm
by Chris
...but the first that comes to mind, is to make the class in Project2 inherit form the one in Project1, like CLASS dbTABELLEchild inherit dbTABELLE. Then use dbTABELLEchild in Project2, while still using dbTABELLE in Project1.

PARTIAL CLASS

Posted: Tue Feb 28, 2023 6:58 pm
by stefan.ungemach
Wouldn't work since there is too much code relying on the generated classes (i.e. dbTABELLE). But due to the discussion which helped me understanding the PARTIAL concept better I started working with a modified approach. In a nutshell

  • I generate all class declarations without any containing code into one file one level higher (like (2) in the example) - so all classes are known
  • I replaced the ACCESSes fpr each class with an ENUM - these are mostly for code readability, and the ENUM seems to be handled in a different way by the compiler
  • I allow one ore more additional PRGs for each subclass in (2), i.e. dbTABELLE.PRG, which extends the subclass with a PARTIAL statement
I still need to find a solution for the extended logic which only comes in projects higher up the hierarchy...

PARTIAL CLASS

Posted: Tue Feb 28, 2023 7:54 pm
by Chris
Hi Stefan,

Just to be absolutely clear, the PARTIAL statement does not really do anything, it only tells the compiler that a class may span in several prg files in the same library, its memebrs will (or may) not be all defined within a certain CLASS...END CLASS construct. This was not needed in VO, because there was no concept of this CLASS...END CLASS container construct, this is the only reason why it is needed in X#. But it does not "extend" the class in any way.

Another thing that you could look into, is extension methods. Those are basically functions, but with special semantics, which make them appear like they are indeed extending a class in different libraries. This is not really the case, they can only access public members of the class (exactly like a function would be able to) and can only be methods, not ACCESS/ASSIGNs, but nevertheless they could be another option (in some cases), depending on the architecture of your system.