Named arguments for ABL procedures.

I understand the temptation in old ABL code, but if you move to OO, you can encapsulate the temp-table in an object and never have the problem again.

Alas, it's not that simple. Unless you want to spend your time writing dynamic code to manipulate temp-tables - and, sure, we all have a somewhat masochistic streak, what with being ABL programmers :D - you will need a temp-table definition in more than one piece of source code.

We can argue the toss on other uses for include files and preprocessors but there's too much power in FOR EACH tTab to give it up to OO encapsulation. And the cost of not putting temp-table definitions in includes is too dear for my thinking.
 
IMO Temp Table definitions are one of the very few legitimate uses for includes these days, so long as you only include them where they are actually used! Where includes are a bane is when there's one or two includes that have hundreds of definitions and functions/procedures that are included everywhere and very little, if anything, is actually used. One codebase I worked with had such an include file and when you did a compile listing you didn't hit actual useful code until many thousands of lines down. And that include was in every piece of code. Wasted bloat and effort.
 
We use include files solely for tt definitions that need to be tossed around and we only define one temp-table per include. Exception is a dataset where the complete definition is in one include. The name of the include is always the same as the name of the include file, so we have calls like {inc\ttProduct.i}.
 
We can argue the toss on other uses for include files and preprocessors but there's too much power in FOR EACH tTab to give it up to OO encapsulation. And the cost of not putting temp-table definitions in includes is too dear for my thinking.

Why not encapsulate the for each in the same object as the temp-table? One of the benefits is that one can change the definition of the temp-table and its access without changing the methods of the object.
 
Why not encapsulate the for each in the same object as the temp-table? One of the benefits is that one can change the definition of the temp-table and its access without changing the methods of the object.

Probably because "the" FOR EACH is awfully optimistic.

Sure, you could do stuff with dynamic queries but that's going to be a lot more complex and may introduce performance concerns.
 
I'll bet that the vast majority of cases are easily encapsulated, some take a bit of thought (which becomes routine after the first few), and a small number are genuinely difficult ... but that often the difficulty exists in the non-OO implementation as well.
 
Hi everyone,

I've been playing with the ABL preprocessor...a scary place indeed. I suspect from the relative lack of discussion of it online that it isn't terribly widely used. I think I've mastered supplying arguments (both numbered and named) to include files, which is great. However I've only been able to get numbered arguments to work in procedure (.p) files. (I've not been able to find anything in the documentation or online to confirm that this is expected behaviour though...)

I'll settle for numbered arguments if I have to, but named arguments are inherently self-documenting and less likely to be mislabelled as a consequence of careless future revisions.

(PS I've found the documentation of procedure arguments pretty limited by Progress standards. And I'm sure that one or two of the (Progress) pages I did find confuse arguments and parameters which is a little worrying....)

(Just to invite the usual well-meaning advice (and abuse :)), I'm using OE 11.1.)

Thanks for reading and any comments you may have.

Allan Green

-------------------------

Here are my latest attempts to get this working just so you can see what I am trying to do!
Code:
/*    Name: forum_submission_parent.p

      Description: This module sets up the values of named arguments
                "argument1" and "argument2" passed to
                forum_submission_daughter.p
*/

&SCOPED-DEFINE cArgument "Teststring"
&SCOPED-DEFINE iArgument 123

RUN forum_submission_daughter.p {
   &cArgument="Teststring"
   &iArgument = 123
   }.

RETURN.

----------------------

/*     Name: forum_submission_daughter.p

       Description: This module was written to clarifiy whether it is
                 possible to use named arguments within an OpenEdge
                 external procedure file.
*/

DEFINE VARIABLE cLocalExample AS CHARACTER FORMAT "x(12)".
DEFINE VARIABLE iLocalExample AS INTEGER FORMAT ">>>9".

cLocalExample = {&cArgument}.
iLocalExample = {&iArgument}.

DISPLAY cLocalExample
        iLocalExample
        WITH FRAME fNamedArgsIncFile
             ROW 5 COLUMN 5
             TITLE "Procedure file daughter".

RETURN.
Hi,

Some examples:
Code:
/*         loadpaire.i
         Load of a combobox or a list
         ==================*/

                    DO :
            
&SCOP       I               {&SEQUENCE}
Def VAR     L-{&I}       AS CHAR            NO-UNDO. 

&IF "{&OBJECT}" = "" &THEN
    &SCOP OBJECT    {&WIDGET}
    &ENDIF

                   
For each {&File} NO-LOCK    
                 WHERE {&WHERE}
                  {&BREAK} :
        L-{&I} = L-{&I} + chr(9) + {&Field} + chr(9) + {&Key}.
        END.
       
&IF DEFINED( UNDEFINED ) > 0 &THEN
           L-{&I} = "{&UNDEFINED}" + chr(9) + " " + L-{&I}.
&else
           L-{&I} = substring( L-{&I}, 2 ).
&endif

ASSIGN  {&object}:DELIMITER     = chr(9)
        {&object}:LIST-ITEM-PAIRS = L-{&I}        NO-ERROR.

                    END.
°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
to use with { loadpaire.i &object=Combo-Box-1  &file=customer &where = "name begins 'A' &BREAK = "By name" }

/*         load.i
            with rowids in te private-data
             ==================*/
            
&SCOP       I               {&SEQUENCE}

Def VAR     L-{&I}       AS CHAR            NO-UNDO.     
Def VAR     P-{&I}       AS CHAR            NO-UNDO.    

&IF "{&OBJECT}" = "" &THEN
    &SCOP OBJECT    {&WIDGET}
    &ENDIF
   
&IF DEFINED( UNDEFINED ) > 0 &THEN
                    L-{&I} = "{&UNDEFINED}".
                    &ENDIF

For each {&File} NO-LOCK    
                          WHERE {&WHERE}
                          {&BREAK} :
        ASSIGN             L-{&I} =   L-{&I}  +  chr(9) + {&Field}.
                           P-{&I} =   P-{&I}  + "," + String(  Rowid( {&File} ) ).
        END.
       
&IF DEFINED( UNDEFINED ) = 0        &THEN
        ASSIGN      {&OBJECT}:DELIMITER         = chr(9)
                            {&OBJECT}:LIST-ITEMS           = SUBSTRING( L-{&I}, 2)
                            {&OBJECT}:DRIVATE-DATA     = SUBSTRING(P-{&I}, 2).
&ELSE
        ASSIGN      {&OBJECT}:DELIMITER         = chr(9)
                            {&OBJECT}:LIST-ITEMS           = L-{&I}
                            {&OBJECT}:PRIVATE-DATA     = P-{&I}.                           
&ENDIF                           

  /* First entry ==> default */
            {&OBJECT}:SCREEN-VALUE = ENTRY(1, {&OBJECT}:LIST-ITEMS, {&OBJECT}:DELIMITER).
°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
 
Last edited by a moderator:
I don't know about anyone else, but I'm very suspicious of a PDF attachment that claims to contain source code. PDF files are often used to distribute malware.

Is there a reason you can't post the code or, at worst, attach a .txt file?
 
Aaaarch, keep that include code away from my eyes!

R3Ic1cK.png


Why not use something like this:
Code:
  RUN fillCombo
    ( cbCustomer:HANDLE
    , "FOR EACH customer NO-LOCK"
    , "cust-num,name"
    ).

Code:
/* Fill a combo box
*/
  DEFINE INPUT PARAMETER phCombo AS HANDLE    NO-UNDO.
  DEFINE INPUT PARAMETER pcQuery AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER pcKeys  AS CHARACTER NO-UNDO.
 
  DEFINE VARIABLE cTable  AS CHARACTER NO-UNDO.
  DEFINE VARIABLE hBuffer AS HANDLE    NO-UNDO.
  DEFINE VARIABLE hQuery  AS HANDLE    NO-UNDO.
 
  cTable = ENTRY(LOOKUP('EACH',pcQuery,' ') + 1, pcQuery,' ').
 
  CREATE BUFFER hBuffer FOR TABLE cTable.
  CREATE QUERY hQuery.
  hQuery:ADD-BUFFER(hBuffer).
  hQuery:QUERY-PREPARE(pcQuery).
  hQuery:QUERY-OPEN.
 
  phCombo:LIST-ITEM-PAIRS = ?.
  REPEAT WHILE hQuery:GET-NEXT:
    phCombo:ADD-LAST( hBuffer:BUFFER-FIELD(ENTRY(2,pcKeys)):BUFFER-VALUE
                    , hBuffer:BUFFER-FIELD(ENTRY(1,pcKeys)):BUFFER-VALUE ).
  END.
 
  hQuery:QUERY-CLOSE.
  DELETE OBJECT hBuffer.
  DELETE OBJECT hQuery.
 
END PROCEDURE. // fillCombo

See attached demo, it needs a truckload of checks, but it shows the power of dynamic coding
 

Attachments

Last edited:
Back
Top