2b: I'm not particular fond of implicit temporary fields and extra moves, but at the moment I can't think of a better idea. And remember, any "ANY LENGTH" field has to support being passed both fixed length fields and DYNAMIC LENGTH fields (doesn't it?), so, unless you want to somehow pass in if it's being passed a fixed or dynamic length fields, and have two separate code paths generated depending (I think) on that type, I don't know how you would support it. (I hope this muddled paragraph makes sense.)
As for returning items, I don't know enough about how they are handled internally to make much of an intelligent comment. Is a temporary item even necessary? I can see where if you "moved" a function that returns 1000 bytes to a field of 100 bytes, you have to allocate the 1000 byte field and (I assume) pass the address of that temp field to the function. The function populates it, and upon return the temp field is moved to the destination field using COBOL padding/truncation rules. But for an ODO, can't you do the same basic thing as for when an ODO is a parameter, and simply pass the address of the actual field? The number of occurances must still be passed as a separate parameter. The function would handle it just like it would if passed an ODO as a parameter. That is, it would update the field whose address it was passed (the destination that is being "returned into"). So as long as the caller passes the correct number of occurances as are actually defined in the callers program, all should work. I think!
All that being said, your bullet 5 seems to imply that "bounded" ODO tables should be able to be used as returning items. If I declare a returning item as "occurs 0 to 999999999 times depending on occur-cnt", are you allocating a PIC X(999999999) temp field? I am hoping not, but it's sounding like maybe you are.
Original Message:
Sent: Thu October 09, 2025 05:23 PM
From: Jeffery Shimoda
Subject: Newer COBOL features, what should next?
Regarding 1 - for the benefit of people following this thread - I had a brief offline exchange with Frank where we came to an understanding the 6.4 "strict" conformance behavior should probably remain. IBM may be reverting the 6.5 behavior in the near future.
2. ANY LENGTH, here are my responses:
- I agree my suggestion for ANY LENGTH is functionally already achievable using unbounded ODO items, so perhaps it doesn't enhance the user's abilities as you would like. ANY LENGTH, in this form, would amount to syntactic sugar with the extra caveat where the item needs to be reference-modified when used. It does look like a much cleaner definition, IMO. And it removes the dependence on the OCCURS object, which may be both good and bad.
- I like the idea of implementing ANY LENGTH using dynamic length items as a means of passing the item as a parameter, though I'm not fond of the compiler-generated intermediate steps (on the caller side) of copying the data into the dynamic length temporary, and copying it back out after the call. Still, this avenue of approach is worth investigating, I think.
3. I agree that dynamic-length strings as returning items on UDFs should be supported. Support for this is not trivial, however.
4. How unbounded ODO items as returning items on UDFs would work is not clear to me because it is the caller that allocates the memory for the returning items of (programs and UDFs). In the case of UDFs, the caller looks at the definition of the UDF returning item to determine what kind of temporary needs to be allocated. If that item is unbounded, then the caller cannot know how much to allocate.
5. I will open an internal issue for the "bounded ODO" crash.
------------------------------
Jeff Shimoda
IBM Enterprise COBOL for z/OS
Compiler Developer
Original Message:
Sent: Wed October 08, 2025 02:44 PM
From: Frank Swarbrick
Subject: Newer COBOL features, what should next?
Hi Jeffery,
First, item number 1 seems to me (if I am understanding correctly) not a great idea. So if I have a function that has a PIC X(256) parameter, and I pass it a PIC X(1000) parameter, are you saying that no error will be given? Seems to me if there is data past character 256 it will simply be silently ignored, right? Or am I totally misunderstanding what you are saying here?
Item 2 can basically be done now, even without ANY LENGTH, at least for input parameters. The input parameter that we want to accept a string of, well, any length, can be defined using an group item that contains an unbounded ODO table with each table element being one byte (PIC X). This, of course, requires an additional length parameter to be passed as well. Here's an example.
01 string-in.
05 pic x occurs unbounded depending on strlen.
01 strlen pic 9(9) comp.
procedure division using reference string-in value strlen ...
No reference modification is required, because the length is taken from the value of strlen.
Another option that is currently possible for an input parameter is to pass a dynamic length string as the parameter. Using this method there is no explicit length field, since it is implicit "within" the field itself. However, generally "source input" strings are fixed length, so a "temporary" dynamic length string field must be defined, then there must be an explicit move of the fixed length string to the dynamic length string and then the function is called using the dynamic length string as the input parameter. Furthermore, if the input string is updated by the function then after the call to the function one would have to move the dynamic length string back to the fixed length string.
Additionally, one still can only use fixed length strings as returning items. I tried the following alternatives, but none of them worked (correctly or at all):
"Allowed" (function compiles), but attempt to invoke the function gets a compiler error with RC-0016:
- Bounded (occurs 0 to 999999999) ODO as returning item
Not allowed at all:
- Dynamic length string as returning item
- Unbounded ODO as returning item
So to summarize, here are options that are allowed and function correctly:
- Fixed length string as both input and output (returning item).
- Downsides: Input field, if shorter than defined parameter, must be passed using CONTENT-OF intrinsic function.
- Unbounded ODO as input; fixed length string as returning item.
- Downsides: Must pass length of input field in addition to the field itself.
- Dynamic length string as input; fixed length string as returning item
- Downsizes: If desired input is a fixed length string it must be moved to dynamic length string first, and that dynamic length string is used as the input parmameter
And all 3 have the downside that the returning item must be fixed length.
All of this is to say that none of these options are "ideal", in my opinion.
I do have an idea that I'd like to present. What if ANY LENGTH was implemented something like the following:
- An ANY LENGTH parameter would behave in the same manner as a DYNAMIC LENGTH parameter.
- On the caller side, the compiler would do the following for any fixed length field being passed as an ANY LENGTH parameter.
- A temporary dynamic length field would be created by the compiler, and the value of the fixed length field would be placed in it.
- The temporary field would be passed as the parameter instead.
- Upon return from the function, the value of the dynamic length string would be placed back in the fixed length field.
- Of course if the parameter is already a dynamic length field then it would be passed as the parameter, and no additional value moves would be required.
Additionally, ANY LENGTH fields (and dynamic length fields, for that matter) should be allowed as returning items.
Finally, a few additional questions:
- Can issue with using "bounded ODO" group be fixed?
- Why can't an unbounded ODO group be used as a returning item?
- Why can't a dynamic length string be used as a returning item?
Here are the prototype definitions of some examples:
id division.
function-id. CompressSpaces as 'CMPRSSPC' is prototype.
data division.
linkage section.
01 string-in pic x(50000).
01 string-out pic x(1000).
procedure division using string-in returning string-out.
end function CompressSpaces.
id division.
function-id. CompressSpaces-1 as 'CMPRSSP1' is prototype.
data division.
linkage section.
01 string-in.
05 pic x occurs unbounded depending on str-in-len.
01 str-in-len pic 9(9) comp.
01 string-out pic x(1000).
procedure division using string-in value str-in-len
returning string-out.
end function CompressSpaces-1.
id division.
function-id. CompressSpaces-2 as 'CMPRSSP2' is prototype.
data division.
linkage section.
01 string-in.
05 pic x occurs unbounded depending on str-in-len.
01 str-in-len pic 9(9) comp.
01 str-out-len pic 9(9) comp.
01 string-out.
05 pic x occurs 0 to 999999999 depending on str-out-len.
procedure division using string-in value str-in-len str-out-len
returning string-out.
end function CompressSpaces-2.
id division.
function-id. CompressSpaces-3 as 'CMPRSSP3' is prototype.
data division.
linkage section.
01 string-in pic x dynamic length.
01 string-out pic x(1000).
procedure division using string-in returning string-out.
end function CompressSpaces-3.
And here is a test program:
copy prototyp.
identification division.
program-id. cmprstst.
environment division.
configuration section.
repository.
function CompressSpaces
function CompressSpaces-1
function CompressSpaces-2
function CompressSpaces-3
function all intrinsic.
data division.
local-storage section.
01 string-in.
05 pic x(40000) value spaces.
05 pic x(100) value 'a b c'.
01 any-string pic x dynamic length.
01 string-out pic x(140).
procedure division.
move CompressSpaces(content-of(string-in)) to string-out
display '"' trim(string-out) '"'
move CompressSpaces-1(string-in length(string-in))
to string-out
display '"' trim(string-out) '"'
*** This one causes a compiler error rc=0016
*> move CompressSpaces-2(string-in length(string-in)
*> length(string-out))
*> to string-out
move trim(string-in) to any-string
move CompressSpaces-3(any-string) to string-out
display '"' trim(string-out) '"'
goback.
end program cmprstst.
------------------------------
Frank Swarbrick
Original Message:
Sent: Mon October 06, 2025 11:20 AM
From: Jeffery Shimoda
Subject: Newer COBOL features, what should next?
Hi Frank, I want to expand on two things (and for those unaware, I work for IBM on the Enterprise COBOL compiler)
- Starting in Enterprise COBOL 6.5 (GA, June 2025), we've lifted the strict requirement of matching the function argument with the formal parameter length, for PIC X, PIC N, and PIC U strings: now the function argument can be longer than the formal parameter without getting a compiler error message (you will still get an error for an argument shorter than the formal parameter). However there was basically no way for you to know about this - my bad on the communication. The docs weren't properly updated either (including the migration guide!) -- I'm working to sort that out. This relaxation of the rules should mitigate the situation a bit.
- As you correctly point out, ANY LENGTH has a somewhat nasty implementation problem - passing the length implicitly. However, I did have one idea that circumvents the implicit length problem: in order to use an ANY LENGTH item, you need to reference-modify it. A non-reference-modified ANY LENGTH item would result in a compile time error. There is no implicit length and therefore the compiler does not have to pass a hidden length from caller to callee. Additionally, this could be allowed on outer programs.
The downside is that it is now the COBOL programmer's responsibility to pass the length as another parameter, then use it to reference-modify the ANY LENGTH item. Does that negate the intended purpose of ANY LENGTH?
I will admit that I don't think the COBOL standard intended for ANY LENGTH items to be _only_ reference-modified - though such an implementation would not be incompatible with the standard - it may be viewed more of a subset of ANY LENGTH functionality.
Thoughts?
------------------------------
Jeffery Shimoda
Original Message:
Sent: Fri October 03, 2025 03:00 PM
From: Frank Swarbrick
Subject: Newer COBOL features, what should next?
Open discussion.
I have been using user defined functions (and function prototypes) quite a bit recently. They are nice, but there is currently one limitation that I consider to be pretty undesirable. The data division "ANY LENGTH" clause, defined in the most recent COBOL standards, is not yet supported. Here is what the standard says about this feature: "The ANY LENGTH clause specifies that the length of a linkage section item may vary at runtime and is determined by the length of the argument in the calling program, method, or function."
Basically, in the called routine (function or contained program) you can define a field in the linkage section with this ANY LENGTH clause, rather than having the length explicitly defined as part of the PICTURE clause. This means, in theory, that a string of, well, any length could be passed as an argument ("actual parameter") and the called routine would treat the corresponding formal parameter as having the same length of that (passed) argument.
As it stands currently, in the linkage section you must choose a specific size. This size may be "too small" or "too large", since you really don't know what size strings users might want to call with. Additionally, if you want to call it with a field that is smaller than the formal parameter defined in the function you either have to manually move it to a temporary field of the require size and pass that instead, or you have to pass it via an invocation of the CONTENT-OF intrinsic function (which will do this "under the covers"). And of course if you have a string larger than the size of the formal parameter, you have to write a new function that does exactly the same thing as the existing one, except allowing for larger input, or you can update the current one and recompile all modules that currently invoke it (possibly with changes if you did not use the CONTENT-OF method). All in all "not ideal".
I will say I understand why ANY LENGTH has not been chose to be supported up to this point. The behavior of this feature would require some sort of implicit passing of not only the address of the passed field but also its actual length. So it would likely either have to be passed implicitly as a separate "unseen" parameter, or maybe passed some other way (maybe a show parameter list pointed to by register 0 or something). Currently COBOL, as far as I know, doesn't do anything like this, so I can see how its implementation might not be "straight forward". That being said, it seems to me that it needs to be supported to make certain types of user defined functions truly useful.
In fact, I would also like to see this feature allowed for "outer" programs and not used contained (nested) functions. The COBOL standard says this is not supported: "The ANY LENGTH clause cannot be specified in an outermost program. This is because an outermost program can be called with or without a program-prototype format CALL statement. For calls without a program-prototype, this International Standard does not require an implementation to determine whether an argument corresponds to a formal parameter described with ANY LENGTH." While I understand the reasoning, I think it could possibly be worked around. Firstly, program prototypes would have to be supported. Then it seems to me there would have to be some way (perhaps passing another "implicit argument") for the activated program to know if it was invoked using a program prototype. If it was invoked in any other manner (legacy COBOL call; call from a non-COBOL program; invoked directly by the operating environment (such as EXEC PGM=MYPROG in JCL)), if one of the formal parameters contains the ANY LENGTH clause, the program could abend. Essentially, an outermost program containing an ANY LENGTH parameter would not be able to be invoked by any other method than from a COBOL program calling a "program prototype".
Curious to hear what others think about this. And are there any other features that IBM should give priority to implementing? (I am just a user of Enterprise COBOL; I don't work for IBM or anything.)
Here is a simple (if not particularly realistic) example of how a COBOL UDF might utilize this feature.
identification division.
function-id. string-validate-and-fix as 'STRVALFX'.
environment division.
configuration section.
repository.
function all intrinsic.
data division.
local-storage section.
77 pos pic s9(9) comp.
linkage section.
01 string-in pic x any length.
01 replacement-char pic x.
01 string-out pic x any length.
procedure division using reference string-in
value replacement-char
returning string-out.
routines section.
mainline.
move string-in to string-out
if string-out is alphabetic
continue
else
perform update-invalid-chars
end-if
goback.
update-invalid-chars.
perform varying pos from 1 by 1
until pos > length(string-out)
if string-out(pos:1) is alphabetic
continue
else
move replacement-char to string-out(pos:1)
end-if
end-perform
exit.
end function string-validate-and-fix.
And here is how it could be used.
move string-validate-and-fix(my-string ' ') to my-string
The my-string field could be defined as PIC X, or PIC X(99999999), or anything in between (or even larger) and it should work.
------------------------------
Frank Swarbrick
------------------------------