CD_Popup_Object in depth

As we have talked about how to identify all the non-deferred objects in the past, one couldn't help but wonder how it all works. I remember when I first started programming in VDF 7 (2001), you just had to change the property "Defer" in the property panel in the IDE (it was not called "Studio"), and boom, your view/modal panel had just become "Deferred". Let's look at some code.

// Non-deferred Version
Object oPanel is a ModalPanel
	Property Integer piValue 0
End_Object

// Deferred Version
CD_Popup_Object oPanel is a ModalPanel
	Property Integer piValue 0
CD_End_Object

From the implementation point of view, it's pretty simple. However, in the Dfdafmac.pkg, it reveals something pretty interesting.

#COMMAND Cd_Popup_Object R
    #PUSH !g
    
    Register_Object !1_cd

    Object !1 is a CD_Client
    
    Function Popup_Handle Returns Handle
        Handle hoID
        Get Created_Object_Id to hoId
        If (hoId=0) Begin
            #SET G$ !a
            Gosub !1_Sub!g
            Move (!1_cd(Self)) to hoId
            Set Created_Object_id to hoID
        End
        Function_Return hoID
    End_Function

   End_Object
    
    [Found ~Found] Begin
    !1_Sub!g:
       #POP R$  
       #POP G$  
       #PUSH !r
       Object !1_cd !2 !3 !4 !5 !6 !7 !8  !9

#ENDCOMMAND

#COMMAND CD_END_OBJECT .
     End_Object
     Gosub_Return
   End
#ENDCOMMAND

Class CD_Client is a Container

    Procedure Construct_Object
        Forward Send Construct_Object
        Property Integer Created_object_id 0
        Set focus_mode to nonfocusable
    End_Procedure // Construct_Object
    
    Procedure Popup
        Send Popup_Modal
    End_Procedure // Popup

    Procedure Popup_Modal Returns Integer
        Integer iRet
        Handle hoId
        Boolean bDestroy
        Get Popup_Handle to hoId
        If hoId Begin
            Get msg_Popup_Modal of hoId to iRet
            Get Destroy_Object_State of hoId to bDestroy            
            If bDestroy Begin
                Send Destroy of hoId
                Set Created_Object_Id to 0
            End
            Procedure_Return iRet
        End
    End_Procedure

End_Class

When you defer a modal panel, VDF does a few things for you (based on the above example)
  1. It creates a dummy CD_Client object named "oPanel"
  2. Your actual modal panel is now named "oPanel_CD"
  3. The entire code for the "oPanel" (technically "oPanel_CD") is now inside a gigantic block of "IF" (Look for the line 22), which will always be false becasue the expression [Found ~Found]. Which means the "IF" block (all the code for the modal panel) will be skipped over.
  4. If you evaluate the Name of the actual modal panel, it has now become "oPanel.oPanel_CD" instead of just "oPanel". That means the dummy CD_Popup_Object (oPanel) is now the parent object of the actual modal panel (oPanel_CD)
  5. When you make a Popup call to oPanel, the dummy CD_Client object will jump the code straight inside the "IF" block (line 13 and 23), this is the time where the actual code for the modal panel gets executed.
Basically put, VDF uses of "GoSub" to skip over some of code execution until you need it. If you look at the implementation of CD_End_Object, it's almost comical that they are just simple "End_Object" and "Gosub_Return" statements. Imagine if you have thousands of modal panels in your program (selection lists included), deferring the modal panels will definitely decrease the startup time of your program. Therefore it is highly recommended that you defer all your modal panels. Pay attention to item #4 - it has burned me in the past. The actual modal panel is now the child of a Container, which usually isn't a big deal. We will cover that more in the future article.