Weird problem with RESIZEing an X-Group

Dear fellow Natural developers :slight_smile:

I’ve got a weird problem using RESIZE on an X-Group. Given this minimal example of my modules…

PDA SMTESTP

DEFINE DATA PARAMETER
 1 SMTESTP
   2 GROUP (1:*)
     3 FIELD1 (A8)
     3 FIELD2 (A8)
END-DEFINE

Program SMTEST

DEFINE DATA
LOCAL USING SMTESTP
END-DEFINE
*
RESET SMTESTP
*
PERFORM LOCAL-SUB
*
/* IRRELEV does not exist, but the error occurs before this line so it is never called
CALLNAT 'IRRELEV' SMTESTP.FIELD1(*)
*
INPUT (AD=IO) 'End'
*
DEFINE SUBROUTINE LOCAL-SUB
PERFORM EXTERNAL-SUB SMTESTP
END-SUBROUTINE
*
END

External subroutine EXTERNAL-SUB

DEFINE DATA
PARAMETER USING SMTESTP
END-DEFINE
*
DEFINE SUBROUTINE EXTERNAL-SUB
RESIZE ARRAY SMTESTP.GROUP TO (1:1) /* this line causes the error!
END-SUBROUTINE
*
END

…I get this error:
SMTESTS 0060 NAT1255 Invalid value in ARRAY clause for REDUCE/EXPAND/RESIZE

If I modify the code in any of these three ways, the error disappears:

  1. remove FIELD2 (which is not referenced anywhere) from SMTESTP OR
  2. comment out this line (which is never called at runtime!): CALLNAT ‘IRRELEV’ SMTESTP.FIELD1(*) OR
  3. call EXTERNAL-SUB directly instead of wrapping it with LOCAL-SUB

Could someone please tell me, what the problem with this code is? It looks perfectly fine to me. I debugged the hell out of it but still can’t explain what the problem is…

Best regards,
Stefan

By default, parameters are passed by reference, but you haven’t allocated any space to SMTESTP.GROUP when you execute the PERFORM, so there is nothing to reference - a bit of a contradiction.

In SMTESTP, change the properties of FIELD1 and FIELD2 from “By Reference” to “By Value Result”. This passes the null X-array to the subroutine which passes back an expanded X-array. To verify, I added a DISPLAY and two ASSIGNs to your code.

PERFORM LOCAL-SUB 
DISPLAY *UBOUND (FIELD1)     /* <-- 
        FIELD1 (*) 
        FIELD2 (*)
ASSIGN FIELD1 (1) = 'Field 1'     /* <-- 
ASSIGN FIELD2 (1) = 'Second'      /* <-- 
END-SUBROUTINE

Dear Ralph,

thank you for your answer. I’ll add that to my list of possible solutions above :wink:

I understand your explanation. However, what I don’t understand is why the code works with BY REFERENCE in the PDA when changing one of the things from my list, e.g. unwrapping the external subroutine and calling it directly without the local subroutine. That should change nothing in the way the “empty” array is initialized and passed to the external subroutine. Or does it?

Best regards,
Stefan

Hi Stefan;

I just wandered through the documentation a bit and found the following:

http://techcommunity.softwareag.com/ecosystem/documentation/natural/nat6310win/pg/pg_defi_xarry.htm#sto_xarray

I do not have time to read this through and play with it, but it looks interesting.

steve

  1. FIELD1 is an element of an X-group array. If you don’t change the parameter definition to BY VALUE RESULT, then pass the entire group instead of one element.
CALLNAT 'IRRELEV' SMTESTP.GROUP (*)
  1. By removing FIELD2, you change FIELD1 from an element of an X-Group array to a standard X-array.

  2. I can only guess that LOCAL-SUB causes the X-Group Array to be treated differently because you push EXTERNAL-SUB to a level 3 routine.

Follow Steve’s documentation link to see how X-Group Arrays are treated differently. Consider changing your structure to two X-Arrays.

DEFINE DATA PARAMETER
 1 SMTESTP
   2 GROUP
     3 FIELD1 (A8/1:*)
     3 FIELD2 (A8/1:*)
END-DEFINE
RESIZE ARRAY SMTESTP.FIELD1 TO (1:1)
RESIZE ARRAY SMTESTP.FIELD2 TO (1:1)
CALLNAT 'IRRELEV' SMTESTP.FIELD1 (*) SMTESTP.FIELD2 (*)
  1. Your code works correctly with:
    • NAT639 on WINXP-Pro (the free Community Edition)
    • and NAT427 Service Pack 2 on z/OS.
      NB. I had to comment out your “dummy” callnat because it gets a NAT0082 :slight_smile:
      .
  2. “Which” version of Natural are you using ?

Hi Steve.

I have already read almost everything I could find about X-Arrays in the documentation :wink: Unfortunately, I could not find an answer to my problem there. Or am I missing something?

Best regards,
Stefan

Hi Ralph.

Thanks, that should explain it.

I could do that, but it would violate the principle of “Interface Segregation” (as I translate it to the context of Natural) because the called subprogram does not need (and should therefore not know about) the other parameters except for the given ones.

In fact, I started off doing that but grew tired of adding RESIZEs all over the place when adding a new array (which was necessary quite often during initial development). That lead to bugs because of missed or inconsistent RESIZEs/REDUCEs etc. Because of that I switched over to the X-Group.

Best regards,
Stefan

Hi Peter.

I love these problems :wink:

That’s exactly what it should produce :slight_smile: I just wanted to show that the problem remains even if the subprogram never gets called. In fact, the problem must be a compile time problem since I only need to remove the parameter SMTESTP.FIELD1(*) to make it run and not the whole line.

6.3.8.0 on SUSE Linux Enterprise

Best regards,
Stefan

You mentioned “Interface Segregation”. I have always argued for Subroutine Independence (Subroutine in the generic sense, not in the Natural sense).

I view being able to change the dimensionality of an X array in a subprogram as a violation of Subroutine independence.

Consider: I have a program with an X array presently dimensioned as having ten occurrences. I issue a CALLNAT to a subprogram which changes the array to have only five occurrences. I now try to reference the seventh occurrence of the array. Boom goes my program.

Should a subroutine have the authority to destroy the ability for a program to continue? I personally think not.

Yes, I could have tested the dimensionality after the CALLNAT. I do not think I should have to do this. Forgetting about arrays for the moment, suppose I have a CALLNAT which passes three arguments, #A, #B, and #C. When my program gets control back from the subprogram, any reference to #B causes an abend. In other words, #B is gone. Is this “right”? Should I have to plan for such a possibility when writing a program to use this subprogram? I think not.

One could argue that if I am writing the program and the subprogram, and am the only person authorized to change either, I could get away with this. Logically, the program and subprogram are one logical entity (and an internal subroutine might have sufficed).

I have found that in most shops, even if things start out this way, they quickly change as circumstances dictate another program, or system, would like access to the subprogram. So much for independence, and so much for believing that one can really control such interdependence.

Sorry for the “rant”, but I have only had one cup of coffee so far this morning. Off for more.

steve

Hi Stefan,
It seems that we are guilty of not checking the Empower Knowledgebase …
This is a known problem on SUSE Linux.
It will be solved in NAT6.3.11
Please see:
https://empower.softwareag.com/sl24sec/SecuredServices/KCFullTextASP/viewing/view.asp?KEY=078297-5977224&DSN=PIVOTAL&DST=TCD&HL=1&QUERY=nat1255

Hi Steve,

no need to excuse :wink: Thanks for your thoughts.

In my example the called subprogram IRRELEV (which is replaced by a real subprogram in my case) uses the parameter BY VALUE so it cannot change its dimensions (or at least it has no consequences for the caller). But you’re right about the need to constantly check the dimensions of X-Arrays. After all the errors I got from not checking them I made a habit of doing it every time I access an array…

Wow, this is the first time I have stumbled across a real bug in Natural :slight_smile: At least, now I know that I’m not crazy :wink:

Best regards,
Stefan