PL/I

PL/I

PL/I

 View Only
Expand all | Collapse all

LENGTH applied to function call with a fixed length result elides the function call?

  • 1.  LENGTH applied to function call with a fixed length result elides the function call?

    Posted 08/21/19 07:08 PM

    In this example:

     

     test: proc options(main);

     

        dcl call_count fixed bin(31);

        dcl str char(200) varying;

        dcl l fixed bin(31);

     

        inner: proc returns(char(20));

           call_count = call_count + 1;

           return ('a string');

        end;

        

        call_count = 0;

     

        str = inner();

        l = length(str);

        display('length(str) is ' || l);

     

        l = length(inner());

        display('length(inner()) is ' || l);

     

        display('call_count is ' || call_count);

     

     end;

     

     

     

     

    we see that the function INNER returns a character string with a constant length (of 20.)

    INNER also has a side effect in that it increments a counter.

     

    In the first invocation of INNER, we just have the result assigned to another string, then LENGTH builtin is applied to that string to yield the proper result.

    In the second invocation of INNER, the string itself is never examined; but only the LENGTH is used.

    In the generated code for the second invocation, there is no actual call to the INNER function, so the side-effect that INNER produces (incrementing the counter) is not done.

    The result is that the final DISPLAY statement displays that CALL_COUNT is 1 and not the expected 2.

    Is this correct behavior?  If so, why?  I didn't find anything in the LRM that says a function call can be elided in this manner; and it's a little surprising since the function has side-effects.

     

     

     

     

    tdr


  • 2.  Re: LENGTH applied to function call with a fixed length result elides the function call?

    Posted 08/22/19 08:30 AM

    What happens if you explicitly set the option IRREDUCIBLE on the INNER() procedure?  From the manual, it seems like that should be the default option anyway, but on the other hand, from the behavior you're describing, it sounds like the compiler is treating it as REDUCIBLE.

    PeteKidwell


  • 3.  Re: LENGTH applied to function call with a fixed length result elides the function call?

    Posted 08/22/19 09:20 AM

    Yes - it does look like it's treating the function call as REDUCIBLE.

     

    However, we have similar behavior from a BUILTIN (which can't be so marked.)  Consider this example where we are invoking the DATETIME builtin with a bad string; which should raise the ERROR condition.  

     

     TEST: PROC OPTIONS(MAIN);

     

      DCL D CHAR(100) VARYING;

      DCL L FIXED BIN(31);

      DCL lab LABEL;

     

      DCL bad_pat char(5);

      dcl err_count fixed bin(31);

     

      dcl rc fixed bin(31);

     

     

      ON ERROR BEGIN;

        DCL code fixed bin(31);

        code = oncode();

        DISPLAY('ERROR condition #' || code);

        err_count = err_count + 1;

        GOTO lab;

      END;

     

      /* Check to see that DATETIME is actually invoked */

      /* when only the length is involved. */

      err_count = 0;

      lab = rest;

      bad_pat = 'abcde';

      L = LENGTH(datetime(bad_pat));

     rest:;

      

      display('err_count is ' || err_count);

     

     END;

     

    When you run that, you get:

     

    err_count is              0

     

    If you change the declaration of "bad_pat" to VARYING; then the program works as expected, and you get:

     

    ERROR condition #          2104

    err_count is              1

     

     I think the LENGTH builtin is incorrectly short-circuiting the evaluation of its operand if the the operand is NONVARYING.

     

    And - for completeness, I did the original test with the INNER function declared this way:

     

        inner: proc returns(char(20)) options(irreducible);

           call_count = call_count + 1;

           return ('a string');

        end;

     

    and still got only one call to INNER.

     

     

    Lastly - I checked on the PL/I standard's definition of the LENGTH builtin-in function (length-bif) to see that it requires a complete evaluation of its argument, so that any possible side-effects have been accomplished.  There didn't seem to be a caveat that says you could drop the evaluation of the argument to LENGTH if it is a NONVARYING string. 

     

    Clearly though, there are reasons to apply this simple optimization when possible (e.g. the LENGTH of a reference with no side-effects, or a constant.). I think, perhaps, the compiler is just a little over-zealous?

    tdr


  • 4.  Re: LENGTH applied to function call with a fixed length result elides the function call?

    Posted 08/26/19 04:57 PM

    Sorry for the late reply, but I was on vacation

    But in both of these cases ( length(inner) and length(datetime(...)) ), the compiler intentionally uses just the attributes and optimizes away the calls.

     

    pelderon