ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Parameter Error, RPGLE CallP to CL Procedure

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

  • Parameter Error, RPGLE CallP to CL Procedure

    Okay, I'm not sure what I'm missing here. After 30 years an iSeries programmer, I'm finally trying to fully utilize the benefits of ILE (thanks Scott Klement!) but I can't explain what's happening. I've stripped my code down to the essential:

    MAIN (RPGLE):
    D CLProc PR ExtProc('SUBPROC')
    D SomeValue 15A Value
    D CharParm S 15A
    C Eval CharParm = 'Message'
    C CallP CLProc( CharParm )
    C Eval *InLR = *On

    SUBPROC (CLLE):
    0001.00 PGM PARM(&CHAR15)
    0002.00 DCL VAR(&CHAR15) TYPE(*CHAR) LEN(15)
    0003.00 CHGVAR VAR(&CHAR15) VALUE('Change Msg')
    0004.00 RETURN


    I've created both as *MODULEs, then created the *PGM MAIN. I want to pass a parameter value from the RPG to the CL, allow the CL to change the value, but not affect the original variable. The above code blows up on the CL (line 3) with MCH3601 error because &CHAR15 is *NULL. If I change the RPG prototype from "Value" to "Const," it works without error, but CharParm has changed value (to "Change Msg") when it returns to the RPG. I can?t figure out what?s wrong. The only way I can see to make it work is by creating a trash variable in the MAIN program, evaluate it to CharParm, and pass the new variable to the CL procedure. Any assistance will be greatly appreciated!

  • #2
    You've put "Value" on the RPG prototype, that is what is causing the problem. The CL language does not support receiving parmeters by VALUE, they must be passed by reference instead. In your case, you told the RPG to pass it by value, but the CL is coded to receive the parameter by reference, so you will get a pointer error (if you are lucky!) and it won't work.

    Remove the VALUE keyword from the RPG prototype, that will fix the problem.

    Comment


    • #3
      Originally posted by Coreyville View Post
      ... I want to pass a parameter value from the RPG to the CL, allow the CL to change the value, but not affect the original variable... If I change the RPG prototype from "Value" to "Const," it works without error, but CharParm has changed value (to "Change Msg") when it returns to the RPG...
      To add to what Scott said, there is no way to do that since CL does not have the concept of CONST or VALUE for parameters. The reason CONST works in RPG is that the compiler checks to make sure that the parameter value is unchanged in the called program. If you were to leave off the CONST keyword in a called RPG program but have it in the calling program, you would see the same behavior as calling a CL program.

      Originally posted by Coreyville View Post
      ... The only way I can see to make it work is by creating a trash variable in the MAIN program, evaluate it to CharParm, and pass the new variable to the CL procedure.
      Or you could save the contents of the parameter in the CL program and put it back before you return to the caller.

      Comment


      • #4
        Originally posted by Coreyville View Post
        The only way I can see to make it work is by creating a trash variable in the MAIN program, evaluate it to CharParm, and pass the new variable to the CL procedure. Any assistance will be greatly appreciated!
        I do wonder why you are changing the value in the CL program if you don't want the contents changed?

        Comment


        • #5
          If the RPG parameter is defined with CONST, you can force the compiler to pass a copy of the parameter by making it an expression. An easy way to do that is to add '' to a string, or add 0 to a numeric value.

          C CallP CLProc( CharParm + '')

          Comment


          • #6
            I don't like Barbara's solution. While it may be clear to you and I exactly why and how that works, it won't be clear to the "next guy" who works on this program. They may see this code that does CharParm + '' and say "that doesn't change the value -- so there's no point in it, I'll remove it" and it'll compile and seem to work, and they won't realize that they've opened it up to being changed by the CL program. Or the opposite could happen, they could just be copying the code to use in a similar situation, and not understand why they're doing it... so you perpetuate this adding '' to the string when it's not necessary.

            IMHO, if the CL program needs to work on a copy of the data (so it doesn't affect the original data) then the CL program should simply make a copy of the parameter!

            Code:
              DCL VAR(&WORKCOPY) TYPE(*CHAR) LEN(15)
            
              CHGVAR VAR(&WORKCOPY) VALUE(&CHAR15)
            
              /* now do your work on the copy */
            This makes it very clear what you're doing, and doesn't rely on some "fancy trick" with CONST and an expression on the prototype to make it work. To me, it's much easier to understand and will be much easier to support/maintain down the road.

            Comment


            • #7
              Originally posted by Scott Klement View Post
              I don't like Barbara's solution. While it may be clear to you and I exactly why and how that works, it won't be clear to the "next guy" who works on this program. They may see this code that does CharParm + '' and say "that doesn't change the value -- so there's no point in it, I'll remove it" and it'll compile and seem to work, and they won't realize that they've opened it up to being changed by the CL program. Or the opposite could happen, they could just be copying the code to use in a similar situation, and not understand why they're doing it... so you perpetuate this adding '' to the string when it's not necessary.

              IMHO, if the CL program needs to work on a copy of the data (so it doesn't affect the original data) then the CL program should simply make a copy of the parameter!

              Code:
              DCL VAR(&WORKCOPY) TYPE(*CHAR) LEN(15)
              
              CHGVAR VAR(&WORKCOPY) VALUE(&CHAR15)
              
              /* now do your work on the copy */
              This makes it very clear what you're doing, and doesn't rely on some "fancy trick" with CONST and an expression on the prototype to make it work. To me, it's much easier to understand and will be much easier to support/maintain down the road.
              I agree with Scott's comment re those who come after us. The problem as I see it is that his approach just moves to problem to a different programmer (i.e. the one maintaining the CL) who at some point in the future might just think - "why do I need this copy of the variable - I'll just use the original" and now we're back to the same problem.

              Right now there is no "correct" answer (although Scott's troubles me less than Barbara's) - I think personally I would make the copy of the variable in the caller (i.e. the same effect as the old CALL op-code had available) - that way the program that is affected is also responsible for its own protection.

              But what I'd really like to see the prototype options extended to include BYCOPY (or whatever) to have the effect of CONST with a guarantee that the variable is _always_ copied. COBOL has had this for a long time and it is one of the few (very few) areas in which the language is better than RPG. And yes Barbara - one of these days I'll get round to writing up an RFE on this one.

              Comment


              • #8
                Originally posted by JonBoy View Post
                I agree with Scott's comment re those who come after us. The problem as I see it is that his approach just moves to problem to a different programmer (i.e. the one maintaining the CL) who at some point in the future might just think - "why do I need this copy of the variable - I'll just use the original" and now we're back to the same problem.
                Maybe, but at least it's clear that that is indeed what you're doing. Just using CONST with someone coding var + '' doesn't make it very clear that the purpose is to make a copy of the variable, but declaring a separate variable and copying the data into it makes that clear. You could also put a comment in there that says "make a copy so we don't change the original".

                IMHO, whether you do it in the called routine or in the caller routine should depend on why you're doing it. If the routine is meant to return an output value through the parameter, but the caller doesn't want the changed value, then absolutely the caller should make the copy. But, if this routine is not meant to return output through the parameter, then it should be coded so that it does not change the parameter. And if you need to make a copy as a "work variable" you should do that.

                It'd be extremely sloppy for a routine that's not meant to return output via the parameter to be changing it. And it sure shouldn't be the caller's responsibilty to make sure the routine doesn't change it's parameters!!

                Comment


                • #9
                  Originally posted by Scott Klement View Post

                  <snip>

                  It'd be extremely sloppy for a routine that's not meant to return output via the parameter to be changing it. And it sure shouldn't be the caller's responsibilty to make sure the routine doesn't change it's parameters!!
                  Agreed - it shouldn't be. Perhaps my looking at doing it that way is just symptomatic of a tendency in my programming style to be defensive. A colleague once told me that my code was so defensive she wanted to attack it.

                  Either way I'd still like the option to have a guaranteed copy option on the proto.

                  Comment


                  • #10
                    I have to say that I agree with Scott. My suggestion was a Bad Idea, and I think it's better for the CL program to take care of making the copy of the parameter for it's own use. I agree that a program (or procedure) should only modify a parameter if that's part of the intended result of calling the program.

                    I also agree with Jon that it would be good to have a by-copy option for parameters.

                    Comment


                    • #11
                      Sorry for the delay; I was having profile issues.

                      Thanks everyone for your input. Scott: That's what I suspected, since you don't have the ability to prototype parameters on the CL side. I just couldn't find it explicitly spelled out anywhere. I solved the issue by creating working variables in the CL procedure, and moved the parameter values in. Thanks again to everyone--some great discussion!

                      Comment

                      Working...
                      X