Developing Using Selector Methods

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Developing Using Selector Methods

4D Tech mailing list
I'm wondering, who out there is still actively developing using selector methods?

For a long time now (way back since v6, perhaps even before that...) I have tended to encapsulate all of my code into Project Methods such that Form and Object level methods consist of nothing more than a Case...End Case block of Form Events that then then call an appropriate Project Method. We all pretty much work at some time or another with legacy code that usually has no conventions whatsoever. Any new code I add to such a codebase will follow the selector method convention.

Do you still adhere to the selector method philosophy or have you moved onto an alternative 4D programming style? If so, can you describe it and why you have found it a better approach than selector methods? It's easy to stick with old ways and not adapt to better approaches so I'm interested to learn and explore better techniques within 4D.

One of the reasons I am asking this question is that many years ago there was the wonderful QuickCode Pro plugin written by Aparajita which sadly ceased working with 4D v6, I think. As I recall, prior to that Aparajita had privileged access to the 4D source code to enable QCP to work its magic but at some point that access was rescinded and QCP sadly reached EOL. QCP was perfect for navigating selector methods using the Case tool as this technique often results in large methods.

With 4D 2003, I started to write my own QCP toolbar replacement using native 4D, at the time using the DynamicStructure plugin (that too has disappeared now I think) and some other tricks to read and parse method source code. With newer versions of 4D some new possibilities have opened up and I am considering re-visiting this project in theory without needing to rely on any external plugins. Does anybody already have something like this that that they have written for their own use? Would anybody be interested in such a 4D component?

Thanks for your thoughts and input.

Regards,
 
Narinder Chandi,
ToolBox Systems Ltd.
--



**********************************************************************
4D Internet Users Group (4D iNUG)
Archive:  http://lists.4d.com/archives.html
Options: https://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Developing Using Selector Methods

4D Tech mailing list
Hi Narinder,
I have some thoughts.

To start, with v17 the whole concept of what a form is in 4D is
fundamentally different. I'm talking about building new forms, here, not
tweaking existing ones. One important change is ditching process variables
as form elements. Just stop. Buttons, fields, variables, and so forth do
not need to be in process variables any longer. In fact using them becomes
a liability if you attempt to use the new DIALOG(*) command. And you should
be using this because unlike our previous best-practice of opening new
windows in new processes the thinking now is to have few, like 1, process
for displaying data and opening multiple windows as needed within that
process. I still see a lot of examples coming out of 4D, even 4D technical
support, that use this old approach. I think it's old hands still doing
what's worked and they are in a hurry. Process vars are just not a good
idea on new forms.

But what about the Current Selection and table locking and all? These are
not concerns with ORDA. And if you start opening multiple forms in the same
process and these forms use process vars for buttons or things the value of
all those buttons (but not the Form event) all change each time you change
one. So, ditch the process vars on forms. In fact with an ORDA database I
rarely have more than a handful of process vars at all. What I do always
have is a single object process var and I use this for any process level
data that needs to persist. I use this as my own process data-store instead
of dozens (hundreds) of distinct vars. A lot of code I look at shows an
almost superstitious view of variable handling in 4D that seems to suggest
there is a hierarchy of variable stability starting with IP vars (most
stable) down to local vars (most volatile). I do not believe that has any
basis beyond very old programming habits of 4D devs. But we can probably
have another discussion about that topic alone. ;-)

The other truly radical change in forms is Form.
https://doc.4d.com/4Dv17R5/4D/17-R5/Form.301-4128553.en.html
The significance of Form to the way you setup a 4D form can not be
overstated. And very little of your understanding of forms from pre v17
programming really applies. It will still work, of course, but using Form
and ORDA you can achieve results on a form that would require a lot of
coding to manage using 4D classic. Sometimes I sat back after getting
something to work and just marveled because the actions were so profound
and there was no code - only the setup of the form and the data it worked
with. The blog has some good examples. One I studied a lot is here:
https://blog.4d.com/multilevel-collection-in-different-listboxes/

But getting back to some specifics of your question, I have argued for a
long time about the value of using a 'form controller' method on forms. I
put all the code for the form into that project method and include that
single method in any form object and the form method. You can identify what
object invoked the method using OBJECT get name. It's basically one big
Case of statement with each object identified by name with whatever code
that object needs. And you can add other actions shared by objects on the
form.

I still use this on complicated forms but I've noticed much less need for
object level code with ORDA. Having a single method is also useful, pretty
much required, to take advantage of Dynamic Forms since the 'method'
property of a dynamic form only accepts a project method, you can't include
code. Dynamic Forms are quite useful. They can be applied to a subform
object or a form opened with DIALOG. Managing various complex listboxes,
for example, is a lot easier with dynamic forms than building them in code.
Faster too. For example, I can design my listboxes in a temporary form and
then use FORM Convert to dynamic to get the code for it, save it to a file
and then load it into a subform when needed. Switching between various
listboxes in the same subform becomes simple. And there is no data loading
because the data are already referenced in Form. In classic 4D
accomplishing this sort of thing would require large methods to build the
listboxes and lots and lots of arrays to manage. And it would be really
difficult to change later on.

I really encourage you to take advantage of coming back to 4D to approach
it as a new environment. Unless you are angling to support old projects
don't worry about how we were doing things 15 years ago. Focus on the new
stuff and run with it. That's where the platform is headed. And it's just a
lot more fun, too.



On Thu, Jun 20, 2019 at 7:48 AM Narinder Chandi via 4D_Tech <
[hidden email]> wrote:

> I'm wondering, who out there is still actively developing using selector
> methods?
>
> For a long time now (way back since v6, perhaps even before that...) I
> have tended to encapsulate all of my code into Project Methods such that
> Form and Object level methods consist of nothing more than a Case...End
> Case block of Form Events that then then call an appropriate Project
> Method. We all pretty much work at some time or another with legacy code
> that usually has no conventions whatsoever. Any new code I add to such a
> codebase will follow the selector method convention.
>
> Do you still adhere to the selector method philosophy or have you moved
> onto an alternative 4D programming style? If so, can you describe it and
> why you have found it a better approach than selector methods? It's easy to
> stick with old ways and not adapt to better approaches so I'm interested to
> learn and explore better techniques within 4D.
>
> One of the reasons I am asking this question is that many years ago there
> was the wonderful QuickCode Pro plugin written by Aparajita which sadly
> ceased working with 4D v6, I think. As I recall, prior to that Aparajita
> had privileged access to the 4D source code to enable QCP to work its magic
> but at some point that access was rescinded and QCP sadly reached EOL. QCP
> was perfect for navigating selector methods using the Case tool as this
> technique often results in large methods.
>
> With 4D 2003, I started to write my own QCP toolbar replacement using
> native 4D, at the time using the DynamicStructure plugin (that too has
> disappeared now I think) and some other tricks to read and parse method
> source code. With newer versions of 4D some new possibilities have opened
> up and I am considering re-visiting this project in theory without needing
> to rely on any external plugins. Does anybody already have something like
> this that that they have written for their own use? Would anybody be
> interested in such a 4D component?
>
> Thanks for your thoughts and input.
>
> Regards,
>
> Narinder Chandi,
> ToolBox Systems Ltd.
> --
>
>
>
> **********************************************************************
> 4D Internet Users Group (4D iNUG)
> Archive:  http://lists.4d.com/archives.html
> Options: https://lists.4d.com/mailman/options/4d_tech
> Unsub:  mailto:[hidden email]
> **********************************************************************



--
Kirk Brooks
San Francisco, CA
=======================

What can be said, can be said clearly,
and what you can’t say, you should shut up about

*Wittgenstein and the Computer *
**********************************************************************
4D Internet Users Group (4D iNUG)
Archive:  http://lists.4d.com/archives.html
Options: https://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Developing Using Selector Methods

4D Tech mailing list
Kirk,

Hi. Thanks for that lengthy response! You make a lot of useful points in regards to v17 for sure and in fact I have already been reading up and digesting the implications of the new ways of working in 4D, particularly Form and ORDA. And yes, it totally makes sense to re-think ones approach for future new 4D development.

Of course re-factoring legacy code is a rare opportunity with the vast majority of clients due to cost implications regardless of the benefits so lots of that code will stick around for years to come!

As ever, learning to wield the new features in 4D by experimenting is the order of the day.

Regards,
 
Narinder Chandi,
ToolBox Systems Ltd.
--

    Hi Narinder,
    I have some thoughts.
   
    To start, with v17 the whole concept of what a form is in 4D is
    fundamentally different. I'm talking about building new forms, here, not
    tweaking existing ones. One important change is ditching process variables
    as form elements. Just stop. Buttons, fields, variables, and so forth do
    not need to be in process variables any longer. In fact using them becomes
    a liability if you attempt to use the new DIALOG(*) command. And you should
    be using this because unlike our previous best-practice of opening new
    windows in new processes the thinking now is to have few, like 1, process
    for displaying data and opening multiple windows as needed within that
    process. I still see a lot of examples coming out of 4D, even 4D technical
    support, that use this old approach. I think it's old hands still doing
    what's worked and they are in a hurry. Process vars are just not a good
    idea on new forms.
   
    But what about the Current Selection and table locking and all? These are
    not concerns with ORDA. And if you start opening multiple forms in the same
    process and these forms use process vars for buttons or things the value of
    all those buttons (but not the Form event) all change each time you change
    one. So, ditch the process vars on forms. In fact with an ORDA database I
    rarely have more than a handful of process vars at all. What I do always
    have is a single object process var and I use this for any process level
    data that needs to persist. I use this as my own process data-store instead
    of dozens (hundreds) of distinct vars. A lot of code I look at shows an
    almost superstitious view of variable handling in 4D that seems to suggest
    there is a hierarchy of variable stability starting with IP vars (most
    stable) down to local vars (most volatile). I do not believe that has any
    basis beyond very old programming habits of 4D devs. But we can probably
    have another discussion about that topic alone. ;-)
   
    The other truly radical change in forms is Form.
    https://doc.4d.com/4Dv17R5/4D/17-R5/Form.301-4128553.en.html
    The significance of Form to the way you setup a 4D form can not be
    overstated. And very little of your understanding of forms from pre v17
    programming really applies. It will still work, of course, but using Form
    and ORDA you can achieve results on a form that would require a lot of
    coding to manage using 4D classic. Sometimes I sat back after getting
    something to work and just marveled because the actions were so profound
    and there was no code - only the setup of the form and the data it worked
    with. The blog has some good examples. One I studied a lot is here:
    https://blog.4d.com/multilevel-collection-in-different-listboxes/
   
    But getting back to some specifics of your question, I have argued for a
    long time about the value of using a 'form controller' method on forms. I
    put all the code for the form into that project method and include that
    single method in any form object and the form method. You can identify what
    object invoked the method using OBJECT get name. It's basically one big
    Case of statement with each object identified by name with whatever code
    that object needs. And you can add other actions shared by objects on the
    form.
   
    I still use this on complicated forms but I've noticed much less need for
    object level code with ORDA. Having a single method is also useful, pretty
    much required, to take advantage of Dynamic Forms since the 'method'
    property of a dynamic form only accepts a project method, you can't include
    code. Dynamic Forms are quite useful. They can be applied to a subform
    object or a form opened with DIALOG. Managing various complex listboxes,
    for example, is a lot easier with dynamic forms than building them in code.
    Faster too. For example, I can design my listboxes in a temporary form and
    then use FORM Convert to dynamic to get the code for it, save it to a file
    and then load it into a subform when needed. Switching between various
    listboxes in the same subform becomes simple. And there is no data loading
    because the data are already referenced in Form. In classic 4D
    accomplishing this sort of thing would require large methods to build the
    listboxes and lots and lots of arrays to manage. And it would be really
    difficult to change later on.
   
    I really encourage you to take advantage of coming back to 4D to approach
    it as a new environment. Unless you are angling to support old projects
    don't worry about how we were doing things 15 years ago. Focus on the new
    stuff and run with it. That's where the platform is headed. And it's just a
    lot more fun, too.



**********************************************************************
4D Internet Users Group (4D iNUG)
Archive:  http://lists.4d.com/archives.html
Options: https://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Developing Using Selector Methods

4D Tech mailing list
In reply to this post by 4D Tech mailing list
Narinder:

Kirk has explained how the “form controller” approach works and it is
essentially the same as selector methods. In the past, I avoided that
approach, as I’ll touch on below, but have embraced it fully, starting with
V11.

IIRC, that approach to programming arose in the late 90’s. My impression at
the time was that it was part of the movement in the 4D community to try to
bring OO coding principles into 4D and I saw that as trying to bludgeon a
square peg into a round hole. It is unfortunate that 4D, to this day, is
not an OO language but I hold out hope. Another motivation for that
selector codes was that 4D method names were limited to 15 characters. That
was a significant impediment and I accepted that selector methods were a
way to get around that. My dislike for selector methods was that they
violated the “a method should have one clearly defined purpose” dictum and,
if you looked code quality using the McCabe score, the decision count was
sky high.

In practical terms, it was very hard to track down what routines were
calling what other routines because the “Find in design” feature in 4D was
glacially slow in those versions.    Another issue I ran into was that code
was so intertwined that it could be very hard to decipher. I referred to
that approach as “loopy swoopy” and, actually had one incident where I was
called upon to fix a bug in a body of code that had been written by the
previous programmer and, after studying it for some hours, had to admit to
the client that I needed to rewrite the code because I could not figure out
how the code worked. That was a very painful experience (bruised ego!) and
it reinforced my position against using that approach.

With the release of V11, 4D’s Find in design feature was vastly improved,
fortunately so it became much easier to find where routines are used. By
2007, I had also been programmatically creating wrapper routines for Object
Tools objects for about a decade. That allowed me to move away from process
variables and debugging code was  vastly simplified - I could put a break
point in a setter or a getter, run the code, and the debugger would pop
open. With those improvements, I was able to now use the form controller
approach and I embraced it fully.

Kirk did a good presentation at the last Summit and I’d advise you to get a
copy of it from him. My approach differs somewhat from how Kirk handles
things. IIRC, Kirk’s code reacts to form events. I’ve taken a different
approach which completely avoids coupling. This code pattern, reacting to
the appropriate events, is used in each active object on the form;

C_LONGINT($formEvent_L)
$formEvent_L:=Form event

Case of
: ($formEvent_L=On Data Change)
PROC_FormEventValues_Assign (OBJ_GPBN ("$h_")->)
MARKUP_FC (OBJ_GPBN ("$h_")->)
End case


PROC_FormEventValues_Assign contains this code:

PROC_FocusObjectPtr_Set ($h_;OBJ_FocusPtr_Return )
PROC_FocusObjectName_Set ($h_;OBJ_FocusName_Return )

PROC_CurrentObjectPtr_Set ($h_;OBJ_CurrentPtr_Return )
PROC_CurrentObjectName_Set ($h_;OBJ_CurrentName_Return )

PROC_FormEvent_Set ($h_;Form event)

PROC_gTablePtr_Set ($h_;gTablePtr_Get )

PROC_CurrentFormPage_Set ($h_;FORM Get current page)

 PROC_CurrentFormTable_Set ($h_;Current form table)

 PROC_FunctionName_Set ($h_;”")

PROC_ObjectState_Set ($h_;”")

PROC_FormEventValues_Assign

The OBJ_methods are wrappers for the underlying 4D function and gTablePtr
is a tell that this is a Foundation-based system.
This code is using an Object Tools object but newer code uses a C_Object.


I use that code in every object method rather than the form method because
I ran into issues with how the tab control behaves under certain
conditions. My approach requires more code but it does give me absolute
control over form activity and, as I mentioned, helps decouple my _FC.


The object is the only parameter passed to the form controller and it uses
Case statement and code as shown in this (cleaned up) sample code:

C_LONGINT($h_;$1)
$h_:=$1


  //C_POINTER($currentObject_P)
  //$currentObject_P:=PROC_CurrentObjectPtr_Get ($h_)

C_TEXT($currentObjectName_T)
$currentObjectName_T:=PROC_CurrentObjectName_Get ($h_)

C_POINTER($focusObject_P)
$focusObject_P:=PROC_FocusObjectPtr_Get ($h_)

C_LONGINT($formEvent_L)
$formEvent_L:=PROC_FormEvent_Get ($h_)

Case of
: ($formEvent_L=On Activate)
  //NOP

: ($formEvent_L=On Deactivate)
  //NOP

: ($formEvent_L=On Mouse Enter)

C_TEX
Case of
: (OBJ_GPBN ($currentObjectName_T)=(->[Proposals]Bill_And_Hold))

If (Not(USER_CanSetBillAndHold_Get ($h_)))
PROPOSAL_ToolTip_OM (OBJ_GPBN ($currentObjectName_T);"")
End if

: (PROP_IsSelAddDeleteButton (0;<>pNil;$currentObjectName_T))

If ([Proposals]Bill_And_Hold)
PROPOSAL_ToolTip_OM (OBJ_GPBN ($currentObjectName_T);"")
End if

: ($currentObjectName_T="PROP_Selected_OptnDiscountRateT")
OBJ_GPBN ("PROP_Selected_OptnDiscountRateT")->:="Options Discount:
"+String([Proposals]F030_OptionsDiscountRate*100)+"%"

End case

$h_:=PROC_FormEventValues_Clear ($h_)

: ($formEvent_L=On Mouse Leave)
Case of
: ($currentObjectName_T="PROP_Selected_OptnDiscountRateT")
OBJ_GPBN ("PROP_Selected_OptnDiscountRateT")->:=""
End case

$h_:=PROC_FormEventValues_Clear ($h_)

Else

Case of
: ($formEvent_L=On Clicked)

Case of
: ($focusObject_P=(OBJ_GPBN ("PREF_ShowLineNumberscb")))
PrefsPut ("PREF_ShowLineNumberscb";String(OBJ_GPBN
("PREF_ShowLineNumberscb")->=1))

: ($focusObject_P=(->bAccept))
gDirtyRec_Set (True)

: ($currentObjectName_T="@installBy@")


: ($formEvent_L=On Outside Call)


: ($formEvent_L=On Unload)


: ($formEvent_L=On Load)


End case

End case

End case


In order to reduce coupling, there are very few process variables and the
vast majority of the data is passed in the Object. That’s even easier with
C_Object and dotted notation.

Working with this approach, I do wish that QCP was still available but, as
you’ve detailed, it’s no longer available. It its stead, I’ve come to learn
to use the Find function and to use Ctrl/Cmd-L to navigate through the
code.

This approach does result in large methods which would be catastrophic if a
method were to be corrupted. That seems to be a thing of the past,
fortunately, but that situation can be avoided by frequent backups or using
source code repository.

If you were an advocate of the selector method approach, you’ll take to the
form controller. As Kirk mentions, it’s a very useful approach and I’ve
overcome my conceptual concerns by viewing the FC approach as a being a
flexible dispatcher method so I’ve convinced myself that I’m not violating
the “a method should have one clearly defined purpose” guideline.

--
Douglas von Roeder
949-336-2902


On Thu, Jun 20, 2019 at 7:48 AM Narinder Chandi via 4D_Tech <
[hidden email]> wrote:

> I'm wondering, who out there is still actively developing using selector
> methods?
>
> For a long time now (way back since v6, perhaps even before that...) I
> have tended to encapsulate all of my code into Project Methods such that
> Form and Object level methods consist of nothing more than a Case...End
> Case block of Form Events that then then call an appropriate Project
> Method. We all pretty much work at some time or another with legacy code
> that usually has no conventions whatsoever. Any new code I add to such a
> codebase will follow the selector method convention.
>
> Do you still adhere to the selector method philosophy or have you moved
> onto an alternative 4D programming style? If so, can you describe it and
> why you have found it a better approach than selector methods? It's easy to
> stick with old ways and not adapt to better approaches so I'm interested to
> learn and explore better techniques within 4D.
>
> One of the reasons I am asking this question is that many years ago there
> was the wonderful QuickCode Pro plugin written by Aparajita which sadly
> ceased working with 4D v6, I think. As I recall, prior to that Aparajita
> had privileged access to the 4D source code to enable QCP to work its magic
> but at some point that access was rescinded and QCP sadly reached EOL. QCP
> was perfect for navigating selector methods using the Case tool as this
> technique often results in large methods.
>
> With 4D 2003, I started to write my own QCP toolbar replacement using
> native 4D, at the time using the DynamicStructure plugin (that too has
> disappeared now I think) and some other tricks to read and parse method
> source code. With newer versions of 4D some new possibilities have opened
> up and I am considering re-visiting this project in theory without needing
> to rely on any external plugins. Does anybody already have something like
> this that that they have written for their own use? Would anybody be
> interested in such a 4D component?
>
> Thanks for your thoughts and input.
>
> Regards,
>
> Narinder Chandi,
> ToolBox Systems Ltd.
> --
>
>
>
> **********************************************************************
> 4D Internet Users Group (4D iNUG)
> Archive:  http://lists.4d.com/archives.html
> Options: https://lists.4d.com/mailman/options/4d_tech
> Unsub:  mailto:[hidden email]
> **********************************************************************
**********************************************************************
4D Internet Users Group (4D iNUG)
Archive:  http://lists.4d.com/archives.html
Options: https://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************
Reply | Threaded
Open this post in threaded view
|

Re: Developing Using Selector Methods

4D Tech mailing list
Douglas,

Thanks. Plenty of food for thought in your post too!

Regards,
 
Narinder Chandi,
ToolBox Systems Ltd.
--
 
    Kirk has explained how the “form controller” approach works and it is
    essentially the same as selector methods. In the past, I avoided that
    approach, as I’ll touch on below, but have embraced it fully, starting with
    V11.
   
    IIRC, that approach to programming arose in the late 90’s. My impression at
    the time was that it was part of the movement in the 4D community to try to
    bring OO coding principles into 4D and I saw that as trying to bludgeon a
    square peg into a round hole. It is unfortunate that 4D, to this day, is
    not an OO language but I hold out hope. Another motivation for that
    selector codes was that 4D method names were limited to 15 characters. That
    was a significant impediment and I accepted that selector methods were a
    way to get around that. My dislike for selector methods was that they
    violated the “a method should have one clearly defined purpose” dictum and,
    if you looked code quality using the McCabe score, the decision count was
    sky high.
   
    In practical terms, it was very hard to track down what routines were
    calling what other routines because the “Find in design” feature in 4D was
    glacially slow in those versions.    Another issue I ran into was that code
    was so intertwined that it could be very hard to decipher. I referred to
    that approach as “loopy swoopy” and, actually had one incident where I was
    called upon to fix a bug in a body of code that had been written by the
    previous programmer and, after studying it for some hours, had to admit to
    the client that I needed to rewrite the code because I could not figure out
    how the code worked. That was a very painful experience (bruised ego!) and
    it reinforced my position against using that approach.
   
    With the release of V11, 4D’s Find in design feature was vastly improved,
    fortunately so it became much easier to find where routines are used. By
    2007, I had also been programmatically creating wrapper routines for Object
    Tools objects for about a decade. That allowed me to move away from process
    variables and debugging code was  vastly simplified - I could put a break
    point in a setter or a getter, run the code, and the debugger would pop
    open. With those improvements, I was able to now use the form controller
    approach and I embraced it fully.
   
    Kirk did a good presentation at the last Summit and I’d advise you to get a
    copy of it from him. My approach differs somewhat from how Kirk handles
    things. IIRC, Kirk’s code reacts to form events. I’ve taken a different
    approach which completely avoids coupling. This code pattern, reacting to
    the appropriate events, is used in each active object on the form;
   
    C_LONGINT($formEvent_L)
    $formEvent_L:=Form event
   
    Case of
    : ($formEvent_L=On Data Change)
    PROC_FormEventValues_Assign (OBJ_GPBN ("$h_")->)
    MARKUP_FC (OBJ_GPBN ("$h_")->)
    End case
   
   
    PROC_FormEventValues_Assign contains this code:
   
    PROC_FocusObjectPtr_Set ($h_;OBJ_FocusPtr_Return )
    PROC_FocusObjectName_Set ($h_;OBJ_FocusName_Return )
   
    PROC_CurrentObjectPtr_Set ($h_;OBJ_CurrentPtr_Return )
    PROC_CurrentObjectName_Set ($h_;OBJ_CurrentName_Return )
   
    PROC_FormEvent_Set ($h_;Form event)
   
    PROC_gTablePtr_Set ($h_;gTablePtr_Get )
   
    PROC_CurrentFormPage_Set ($h_;FORM Get current page)
   
     PROC_CurrentFormTable_Set ($h_;Current form table)
   
     PROC_FunctionName_Set ($h_;”")
   
    PROC_ObjectState_Set ($h_;”")
   
    PROC_FormEventValues_Assign
   
    The OBJ_methods are wrappers for the underlying 4D function and gTablePtr
    is a tell that this is a Foundation-based system.
    This code is using an Object Tools object but newer code uses a C_Object.
   
   
    I use that code in every object method rather than the form method because
    I ran into issues with how the tab control behaves under certain
    conditions. My approach requires more code but it does give me absolute
    control over form activity and, as I mentioned, helps decouple my _FC.
   
   
    The object is the only parameter passed to the form controller and it uses
    Case statement and code as shown in this (cleaned up) sample code:
   
    C_LONGINT($h_;$1)
    $h_:=$1
   
   
      //C_POINTER($currentObject_P)
      //$currentObject_P:=PROC_CurrentObjectPtr_Get ($h_)
   
    C_TEXT($currentObjectName_T)
    $currentObjectName_T:=PROC_CurrentObjectName_Get ($h_)
   
    C_POINTER($focusObject_P)
    $focusObject_P:=PROC_FocusObjectPtr_Get ($h_)
   
    C_LONGINT($formEvent_L)
    $formEvent_L:=PROC_FormEvent_Get ($h_)
   
    Case of
    : ($formEvent_L=On Activate)
      //NOP
   
    : ($formEvent_L=On Deactivate)
      //NOP
   
    : ($formEvent_L=On Mouse Enter)
   
    C_TEX
    Case of
    : (OBJ_GPBN ($currentObjectName_T)=(->[Proposals]Bill_And_Hold))
   
    If (Not(USER_CanSetBillAndHold_Get ($h_)))
    PROPOSAL_ToolTip_OM (OBJ_GPBN ($currentObjectName_T);"")
    End if
   
    : (PROP_IsSelAddDeleteButton (0;<>pNil;$currentObjectName_T))
   
    If ([Proposals]Bill_And_Hold)
    PROPOSAL_ToolTip_OM (OBJ_GPBN ($currentObjectName_T);"")
    End if
   
    : ($currentObjectName_T="PROP_Selected_OptnDiscountRateT")
    OBJ_GPBN ("PROP_Selected_OptnDiscountRateT")->:="Options Discount:
    "+String([Proposals]F030_OptionsDiscountRate*100)+"%"
   
    End case
   
    $h_:=PROC_FormEventValues_Clear ($h_)
   
    : ($formEvent_L=On Mouse Leave)
    Case of
    : ($currentObjectName_T="PROP_Selected_OptnDiscountRateT")
    OBJ_GPBN ("PROP_Selected_OptnDiscountRateT")->:=""
    End case
   
    $h_:=PROC_FormEventValues_Clear ($h_)
   
    Else
   
    Case of
    : ($formEvent_L=On Clicked)
   
    Case of
    : ($focusObject_P=(OBJ_GPBN ("PREF_ShowLineNumberscb")))
    PrefsPut ("PREF_ShowLineNumberscb";String(OBJ_GPBN
    ("PREF_ShowLineNumberscb")->=1))
   
    : ($focusObject_P=(->bAccept))
    gDirtyRec_Set (True)
   
    : ($currentObjectName_T="@installBy@")
   
   
    : ($formEvent_L=On Outside Call)
   
   
    : ($formEvent_L=On Unload)
   
   
    : ($formEvent_L=On Load)
   
   
    End case
   
    End case
   
    End case
   
   
    In order to reduce coupling, there are very few process variables and the
    vast majority of the data is passed in the Object. That’s even easier with
    C_Object and dotted notation.
   
    Working with this approach, I do wish that QCP was still available but, as
    you’ve detailed, it’s no longer available. It its stead, I’ve come to learn
    to use the Find function and to use Ctrl/Cmd-L to navigate through the
    code.
   
    This approach does result in large methods which would be catastrophic if a
    method were to be corrupted. That seems to be a thing of the past,
    fortunately, but that situation can be avoided by frequent backups or using
    source code repository.
   
    If you were an advocate of the selector method approach, you’ll take to the
    form controller. As Kirk mentions, it’s a very useful approach and I’ve
    overcome my conceptual concerns by viewing the FC approach as a being a
    flexible dispatcher method so I’ve convinced myself that I’m not violating
    the “a method should have one clearly defined purpose” guideline.
   
    --
    Douglas von Roeder



**********************************************************************
4D Internet Users Group (4D iNUG)
Archive:  http://lists.4d.com/archives.html
Options: https://lists.4d.com/mailman/options/4d_tech
Unsub:  mailto:[hidden email]
**********************************************************************