ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

CONST keyword on prototype

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • CONST keyword on prototype

    I have a program that I am calling as a procedure in another program (CALLP). My intentions were to pass parms 1-3 as input only parms and have the 4th parm modified by RTVLOCOVR and returned to the calling program. This works fine and RTVLOCOVR successfully populates the 4th parameter and returns it to the caller. I suddenly noticed that I specified unintentionally CONST in the the 4th parm of the prototype, so I had to wonder, why does it return a value? Doesn't CONST make it read only?

    Code:
        [FONT=courier new] DRTVLOCOVR        PR                  EXTPGM('RTVLOCOVR')                  
         D                                2    CONST                             
         D                               10    CONST                             
         D                                3S 0 CONST                             
         D                             1024    CONST          [/FONT]


    Here is the procedure being called in the program:
    Code:
         C                   Clear                   wkCmd                          
         C                   Callp     RTVLOCOVR (ORLCFM : 'BOL6      ':            
         C                                1 : wkCmd)


    Here is the prototype in RTVLOCOVR (no CONST specified)
    Code:
     DCL-PI RtvLocOvr;           
        prmLoc Char(2) Const;     
        prmPrtFile Char(10) Const;
        prmKey Zoned(3) Const;    
        prmCmd Char(1024);        
      END-PI;


    As I mentioned RTVLOCOVR appears to return wkCmd successfully populated, I am surprised. Does this work differently than I thought. Does it even matter how the 4th parm is defined (CONST or not)in the calling program. The 2 prototypes don't match in that regard.

  • #2
    May I ask a really stupid question? Why modify the value of a parameter rather than simply return a value?

    But to answer your question - what you show isn't the prototype - but the procedure interface. It doesn't have the CONST so the compiler doesn't treat it as a constant. If you put the CONST there and the procedure modifies prmCMD it will yell at you profusely.

    Comment


    • #3
      If you had:

      Code:
       
        DCL-PI RtvLocOvr;                prmLoc Char(2) Const;          prmPrtFile Char(10) Const;     prmKey Zoned(3) Const;         prmCmd Char(1024) Const;           END-PI;
      And you change prmCmd the compiler will complain.

      I submit though that it would be preferable to have:

      Code:
       
        DCL-PI RtvLocOvr Char(1024);                prmLoc Char(2) Const;          prmPrtFile Char(10) Const;     prmKey Zoned(3) Const;       END-PI;
      Ideally, a procedure has one entry with defined parameters and one exit point with or without a return value. It is ideal not to use a parameter to return values. Now, there's nothing wrong or bad to do so, it's a coding decision but I submit that down the road when somebody is troubleshooting it will be much more straightforward to check the input and the return value rather than looking for how a parameter was changed.

      Comment


      • #4

        If you had:

        Code:
        DCL-PI RtvLocOvr; 
         prmLoc Char(2) Const;
          prmPrtFile Char(10) Const;
          prmKey Zoned(3) Const;
          prmCmd Char(1024) Const;
        END-PI;
        And you change prmCmd the compiler will complain.

        I submit though that it would be preferable to have:

        Code:
        DCL-PI RtvLocOvr Char(1024);
           prmLoc Char(2) Const;
           prmPrtFile Char(10) Const;
           prmKey Zoned(3) Const;
        END-PI;
        Ideally, a procedure has one entry with defined parameters and one exit point with or without a return value. It is ideal not to use a parameter to return values. Now, there's nothing wrong or bad to do so, it's a coding decision but I submit that down the road when somebody is troubleshooting it will be much more straightforward to check the input and the return value rather than looking for how a parameter was changed.

        Comment


        • #5
          You have committed the cardinal sin of not including the prototype in the called program - had you done so the compiler would not have allowed the program to compile due to a PI/PR mis-match. You have lied to the compiler and therefore laid yourself open to problems. It is only permissable to omit prototypes _if_ the called procedure is local to the source. Never ever do it if the called routine (program or procedure) is separately compiled.

          This is the scenario you should have:

          Calling program includes a /Copy RtvLocOvrP (i.e. the proto for RtvLocOvr)

          RtvLocOvr also includes /Copy RtvLocOvrP

          That way if you ever mess up the combination (for example you might have mis-specified one of the lengths) the compiler will catch it.

          The reason the value can change is simple. Const in the calling program means "Please fix the length/size/datatype if possible if what I pass you doesn't match exactly". Const in the called routine means "Thou shalt not allow this value to be changed". You lied to the compiler when compiling the called routine and said it was OK to change the value. If you want to prove this to yourself, simply change the calling program to pass (say) a 100 char field as the 4th parameter. Don't touch the called routine. You'll find that the program will run as before _but_ you won't see the modified value because that went into a temporary variable.


          I should also say that I agree with Rocky that making it a procedure with a return value is preferable - and use RTNPARM if this will be called frequently as 1,024 is a biggish return value.

          As a further note - you're using free-form - why are you still using C-specs - convert the dang thing!

          Comment


          • #6
            Originally posted by JonBoy View Post
            As a further note - you're using free-form - why are you still using C-specs - convert the dang thing!
            Thanks for the explanation, that makes sense.

            I always use free-format when I am writing a new program and the calling program in my example have the sub procedure written in RPG free although the procedure is called from the fixed format portion of the program. However, I am in the midst of a project where I am modifying over 200 existing programs to accommodate the acquisition of another company and I am under extreme time constraints. The programs I am modifying are poorly written to begin with and need to be re-written, which I do not have time for now. So, I am charged with the task of "just making them work". So converting poorly written fixed format programs to free is like putting lipstick on a pig.

            Comment


            • gregwga50
              gregwga50 commented
              Editing a comment
              I stand corrected, the statement "the calling program in my example have the sub procedure written in RPG free " is incorrect. It is actually a separate program written in RPG-free

          • #7
            I submit that with today's systems that a return parm with size of 1024 is insignificant unless you're talking a fairly tight loop of 100's of thousands of iterations. It would be an interesting experiment to see how significant it may or may not be.

            Comment


            • #8
              Originally posted by Rocky View Post
              I submit that with today's systems that a return parm with size of 1024 is insignificant unless you're talking a fairly tight loop of 100's of thousands of iterations. It would be an interesting experiment to see how significant it may or may not be.
              And in this case Rocky I would probably agree BUT ... there's a reason RTNPARM was added. A lot of it had to do with programmers who decide that it would be a good idea to have the called routine return a result set and not just a single item - so they "just" add Dim(1000) to the return value. No problem. Until you run it!

              So these days when I see a size that might be borderline, I usually suggest that the programmer considers the option. At least they are then aware of it and might tend to be on the lookout for it in future.

              Comment


              • #9
                Never hurts to know the options, that's for sure....

                I just created a program that called two procedures. One that returned a char(10), the other a char(32000). I called each 10,000 times. One took 0.001 of a second, the other took 0.87 of a second. So while technically the 32K - over 10,000 iterations, took 870 times as long - you'd still not notice as it didn't even take a second.

                Now - if you had that as char(32000) dim(1000) - now there'd be an issue...

                Comment


                • #10
                  Doing 1024 rather than 10 at 10,000 iterations took 0.005. It took 5 times as long but you could never see the difference....

                  In short - unless your data that you're returning is absolutely ginormous and in a tight loop, I don't know I would bother worith the RTNPARM coding. Nothing wrong with doing it, I'm just a lazy programmer... I certainly wouldn't bother with 1024 or even 10,240.

                  Comment


                  • #11
                    But you are a single user Rocky. What if you are 10,000+ users? Anyway - I'm not disagreeing with you in absolute terms but IBM was sufficiently concerned by the number of serious performance calls they were getting to use up scarce resource to add RTNPARM - it wasn't for fun - it to respond to real issues.

                    Interestingly IBM didn't even think of the side effect of RTNPARM when justifying it. i.e. Being able to use a subprocedure with a return value in Java calls and therefore via the web service wizard.

                    Comment


                    • #12
                      The documentation states:

                      Using RTNPARM may improve performance when returning large values.

                      There will be some improvement when the prototyped return value is a larger value such as a 32767 byte data structure. The performance improvement is most apparent when the prototyped return value is a large varying length string, and the actual returned value is relatively small; for example, the prototype defines the return value as a one million byte varying length character string, and the value 'abc' is returned.
                      They put it at least 32K - and more so if it's defined very very large but oftentimes only a small amount of real data is returned...

                      There's really no real right or wrong or good or bad until you get to the very large amounts of data. Then the need for RTNPARM is more apparent (If the program calls the routine twice in it's entire execution I submit that it's of less concern than if it's ran thousands of times - the former I would tend to have the mentality - who cares if it takes 2 seconds - the latter that 2 seconds adds up pretty quickly).

                      Comment


                      • #13
                        I enjoy these kind of discussions.

                        Comment

                        Working...
                        X