Welcome, Guest
Username: Password: Remember me
Visual Objects

Please use this forum to post questions about Visual Objects and Vulcan.NET
  • Page:
  • 1

TOPIC:

Inheritance 15 Feb 2022 04:24 #21560

  • ThomasWYale
  • ThomasWYale's Avatar
  • Topic Author


  • Posts: 42
  • In my system, there are the following classes:

    CLASS Frame
    CLASS FE
    CLASS FrameEx INHERIT Frame
    CLASS FEEx INHERIT FE (which XSharp VOXPorter converted to PARTIAL CLASS FEEx INHERIT FE)

    Each of these four classes has it's own init method (or rather CONSTRUCTOR method). I anticipated that whatever class is instantiated, it would run that CONSTRUCTOR code. But when I step through through the debugger where an instantiation of FrameEx occurs, and look at the call stack, it appears to be executing the CONSTRUCTOR for FrameEx twice, despite that at the top of the call stack, it's actually executing the CONSTRUCTOR for the inherited class Frame instead (please see screenshot below).

    ).

    Why would the CONSTRUCTOR Frame execute instead of the one for FrameEx? Is it possible that while X# is displaying "FrameEx", X# is ignoring the "Ex" in "FrameEx" and just executing the one with the inherited class with the shortest name? Should the inheriting classes be given a more distinctive name to prevent this from happening?
    Attachments:

    Please Log in or Create an account to join the conversation.

    Last edit: by ThomasWYale.

    Inheritance 15 Feb 2022 08:20 #21561

    • robert
    • robert's Avatar


  • Posts: 3293
  • Thomas,
    Can you share the code?
    Your expectations are correct.
    I can't read the screen shots. Are the "Ex" constructors calling the SUPER() constructors ?

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Inheritance 15 Feb 2022 08:37 #21562

    • Chris
    • Chris's Avatar


  • Posts: 3759
  • Hi Thomas,

    It's the correct constructor that it's being called every time, as you can see the line specified in the 3rd column is different in the two lines.

    The "class" specified in the first column is the actual class name of the active SELF object, which is indeed the name of the last class in the inheritance, not the name of the class where the debugger is pointing at right now in the editor. It is unfortunately a bit complicated to make it show the class name in the inheritance tree, but will give it a try.

    Is there some other problem that you were trying to debug and found this?

    .
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Inheritance 17 Feb 2022 16:00 #21575

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Yes, here it is. Another class instantiates a FrameEx object:

    AAdd(oExSyntaxRef:aFrameEx,(oFrameEx:=FrameEx{nVerbLoc,oVerb,TRUE}))

    These are the class definitions of Frame and FrameEx:

    CLASS FrameEx INHERIT Frame
    EXPORT lPositive AS LOGIC
    EXPORT aFEsLiteral AS ARRAY
    EXPORT aFEsObj AS ARRAY
    EXPORT aRelations AS ARRAY
    EXPORT aRelatedFrames AS ARRAY
    EXPORT nVerbRef AS BYTE
    EXPORT nScore AS BYTE
    EXPORT aEmbeddingFEs AS ARRAY
    EXPORT lFEsConform AS LOGIC
    EXPORT aUnassignedObj AS ARRAY
    EXPORT lViaVN AS LOGIC
    
    CLASS Frame
    EXPORT nRec AS LONG
    EXPORT ccName AS STRING
    EXPORT cDef AS STRING
    EXPORT aFEs AS ARRAY
    EXPORT aGramObjs AS ARRAY
    EXPORT cRelation AS STRING
    EXPORT aEmbedded AS ARRAY

    And the CONSTRUCTORs:

    CONSTRUCTOR(lInitialize) // for Frame
    LOCAL y AS BYTE
    LOCAL cRec AS STRING
    LOCAL aSFE[0],aOFE[0],aOtherFE[0] AS ARRAY
    LOCAL oFE AS FE
    SELF:aGramObjs:={}
    SELF:cRelation:=""
    IF lInitialize
     SELF:nRec:=0
     SELF:ccName:=""
     SELF:cDef:=""
     SELF:aFEs:={}
    ELSE
     SELF:nRec:=RecNo()
     SELF:ccName:=Trim(cName)
     SELF:cDef:=Def
     SELF:aFEs:={}
     cRec:=base16(RecNo(),2)
     DbSelectArea("FE")
     DbSeek(cRec)
     AAdd(SELF:aFEs,FE{TRUE})
     WHILE cRec==nFrame
      oFE:=FE{FALSE}
      IF oFE:nGramSlot=0
       AAdd(aSFE,oFE)
      ELSEIF oFE:nGramSlot=1
       AAdd(aOFE,oFE)
      ELSE
       AAdd(aOtherFE,oFE)
      ENDIF
      DbSkip()
     ENDDO
     FOR y:=1 UPTO ALen(aSFE)
      AAdd(SELF:aFEs,aSFE[y])
     NEXT
     FOR y:=1 UPTO ALen(aOFE)
      AAdd(SELF:aFEs,aOFE[y])
     NEXT
     FOR y:=1 UPTO ALen(aOtherFE)
      AAdd(SELF:aFEs,aOtherFE[y])
     NEXT
     SELF:aEmbedded:=ArrayNew(ALen(SELF:aFEs))
     AFill(SELF:aEmbedded,FALSE)
    ENDIF
    RETURN SELF
    
    CONSTRUCTOR(nVerbRef,oWord,lViaVN) // for FrameEx
    LOCAL nFE1Loc,nFE2Loc AS BYTE
    LOCAL nFE1Rec,nFE2Rec AS LONG 
    LOCAL cRec AS STRING
    LOCAL cElements AS STRING
    SELF:nRec:=RecNo()
    SELF:ccName:=Trim(cName)
    IF SELF:ccName=="Change_position_on_a_scale"
     nFE1Loc:=1
    ENDIF
    SELF:cDef:=Def
    SELF:aFEs:={}
    cRec:=base16(RecNo(),2)
    cElements:="FrameEx:init: "+NTrim(RecNo())+" = "+cRec+CRLF
    cElements+=SELF:ccName+CRLF
    DbSelectArea("FE")
    DbSeek(cRec)
    cElements+="In FE.dbf:"+CRLF+NTrim(RecNo())+CRLF
    WHILE cRec==nFrame
     cElements+=NTrim(RecNo())+CRLF
     DbSkip()
    ENDDO
    DbSelectArea("FE")
    DbSeek(cRec)
    AAdd(SELF:aFEs,FEEx{TRUE})
    WHILE cRec==nFrame
     AAdd(SELF:aFEs,FEEx{FALSE})
     DbSkip()
    ENDDO
    SELF:aEmbedded:=ArrayNew(ALen(SELF:aFEs))
    AFill(SELF:aEmbedded,FALSE)
    DbSelectArea("FEFESAFR")
    DbSeek(cRec)
    WHILE Frme==cRec
     IF RelateType="1"
      nFE1Rec:=base10(FE1)
      nFE1Loc:=AScan(SELF:aFEs,{|x|x:nCNameRec=nFE1Rec})
      nFE2Rec:=base10(FE2)
      nFE2Loc:=AScan(SELF:aFEs,{|x|x:nCNameRec=nFE2Rec})
      IF SELF:aFEs[nFE2Loc]:aSubFEs==NULL_ARRAY 
       SELF:aFEs[nFE2Loc]:aSubFEs:={}
      ENDIF
      AAdd(SELF:aFEs[nFE2Loc]:aSubFEs,SELF:aFEs[nFE1Loc])
      SELF:aEmbedded[nFE1Loc]:=TRUE
     ENDIF
     DbSkip()
    ENDDO
    SELF:aGramObjs:={}
    SELF:cRelation:=""
    SELF:lPositive:=TRUE
    IF!IsNil(oWord)
     SELF:aFEsLiteral:={oWord:cLiteral}
     SELF:aFEsObj:={oWord}
    ENDIF
    SELF:aRelations:={}
    SELF:aRelatedFrames:={}
    SELF:nVerbRef:=nVerbRef
    SELF:nScore:=0
    SELF:aEmbeddingFEs:={}
    SELF:lFEsConform:=TRUE
    SELF:aUnassignedObj:={}
    SELF:lViaVN:=lViaVN
    RETURN SELF
    In VO, only one of these inits is executed, depending on the CLASS. In X#, according to the callstack, both CONSTRUCTORs are executed for some reason. In that case, to answer your question, yes, instantiating FrameEx calls the SUPER() CONSTRUCTOR, which would be Frame:init(), which in X# would be Frame.ctor().

    I circumvented the problem by recoding Frame and FrameEx as two separate CLASSes, as well as encapsulating CLASSes FE and FEex, with no inheritance, and it works fine. I was a little concerned that future developers, however, may require inherited or inheriting CLASSes and face the same problem.

    Please Log in or Create an account to join the conversation.

    Last edit: by ThomasWYale.

    Inheritance 17 Feb 2022 16:06 #21576

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • Yes, the inheritance problem here was separate from another problem that I posted on another forum topic, which dealt with using "RESULT" as a dbf field name. "RESULT" conflicted with an ACCESS attribute for the window that was using it. You suggested inserting "FIELD->(RESULT)" to refer to the field name, and I replaced all occurrences of that in the code specifically for the window. Your solution was excellent, thank you! After that, it worked fine.

    Please Log in or Create an account to join the conversation.

    Last edit: by ThomasWYale.

    Inheritance 17 Feb 2022 16:43 #21577

    • robert
    • robert's Avatar


  • Posts: 3293
  • Thomas,
    In .Net if you have classes and subclasses, then the subclass is expected to call the constructor of the parent class.
    Not calling the parent constructor is a "deadly sin".
    What you can do is to create 2 (or more) constructors in the parent class. The default parameterless constructor can do "nothing" and can be called from the child class.
    If you choose to do it that way then you will have to strongly type the parameters of the parameters of the constructor. You cannot use overloading when one of the constructors has untyped parameters (clipper calling convention).
    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Inheritance 17 Feb 2022 17:14 #21579

    • Chris
    • Chris's Avatar


  • Posts: 3759
  • Hi Thomas,

    There's a trick you can use to avoid this, add the following code anywhere in your FrameEx constructor:

    IF FALSE
      SUPER()
    ENDIF

    this will trick the compiler into thinking you are handling calling the parent constructor yourself, and will not add implicitly code to do it, so the parent will never get called.

    I am sure Robert will call me naughty for this ;)

    .
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Last edit: by Chris.

    Inheritance 17 Feb 2022 17:28 #21580

    • robert
    • robert's Avatar


  • Posts: 3293
  • Chris,



    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    Inheritance 17 Feb 2022 18:05 #21581

    • Chris
    • Chris's Avatar


  • Posts: 3759
  • :D
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    Inheritance 17 Feb 2022 18:06 #21582

    • ThomasWYale
    • ThomasWYale's Avatar
    • Topic Author


  • Posts: 42
  • LOL

    Please Log in or Create an account to join the conversation.

    • Page:
    • 1