Search code examples
rpgle

Share definitions between Prototype and Procedure Interface


I am getting started with RPGLE and I am trying to determine if there is any way of just defining the parameters for the procedures in my service program once. I know I can put the prototypes inside a copy member (which I have done), but then I still have to put essentially the same code into the body of the procedure (the "procedure interface").

My question is, is there some way of using the prototype to define the parameters in the procedure interface (or vice versa)?

Ideally, something like:

Prototype:

D buildForm        PR
D  formType                      10A   CONST
D  mode                           4A   CONST

Procedure:

P buildForm        B
D buildForm        PI
D  formType                            LIKE(formType)
D  mode                                LIKE(mode)

Well, ideally I would just be able to say 'use prototype' or something in the body of the procedure, or the compiler would find it on its own...


Am I misunderstanding how Prototypes and Procedure Interfaces need to be set up, or are they actually this repetitive when done correctly:

Prototype:

D buildForm        PR
D  formType                      10A   CONST
D  mode                           4A   CONST

Procedure:

P buildForm        B
D buildForm        PI
D  formType                      10A   CONST
D  mode                           4A   CONST

Thanks for reading.


Solution

  • On 7.1, if you are defining a sub-procedure in the same program you are using it, you don't need the prototype. You only need the prototype if you're consuming a sub-procedure from a service program or bound module (Don't bind modules to a program!)

    I don't personally find the prototype burdensome to create. I copy the PI, change it to PR, put it into a /copy member and use it in many programs like this:

      /copy buck/qprotosrc,buildform
      ...
      buildform(form: mode);
    

    The only time I need to 'double define' is in the service program where the PI is located. A way to avoid most of that is to use conditional compilation. Here's an example:

    qprotosrc(buildform)

      // Build form prototype and start of interface
      // Service program will complete the interface with P    E
      /if not defined(buildform_proto)
      /define buildform_proto
     D buildForm       PR
      /else
     P buildForm       B
     D buildForm       PI
      /endif
     D  formType                     10A   CONST
     D  mode                          4A   CONST
    

    qrpglesrc(mysrvpgm)

      /copy buck/qprotosrc,buildform
      ...
      /copy buck/qprotosrc,buildform
      // body of buildform here
      ...
       return;
     p                 e
    

    The first time the /copy is processed, it inserts the prototype - this is what you'd want for all your consumer programs. As part of processing, it defines buildform_proto. In your service program, you'd then put a second /copy. Because buildform_proto is defined, the compiler inserts the P...B and D...PI specs. You'd have to supply the procedure body and the P...E spec.