Synopsis
Provide a supported, performant way to obtain metadata about variables at runtime in ILE programs. It can be a language-level built-in function in RPG or a system API callable from any ILE language.
Problem statement
ILE RPG offers only a few introspection BIFs (%SIZE, %LEN, %DECPOS, %ELEM). There is no supported way to determine at runtime:
- its data type (char, packed, zoned, int, date, indicator, pointer, etc.),
the structure of a data structure (list of subfields, offsets, nesting, qualified/template status),
whether it is an array/table/multiple-occurrence DS and its dimensions.
The only workarounds today are fragile or heavy: parsing compiler listings, retrieving debug views through the Debug APIs (which requires debug data and is not intended for production), or hand-maintaining parallel metadata tables. All of these are error-prone and break when the source changes.
Proposed solution
-
BIF (RPG), e.g.
%VARINFO(variable), returning a structure
variable name (as declared), data type, length, decimal positions
dimension / number of elements, DIM/OCCURS information
for data structures: number of subfields and, via an iterator or array, each subfield’s name, type, length, decimals, offset and nesting level
API, e.g. QRNTREF, an ILE-callable service program API that, given a pointer to a variable or a program/module and variable name, returns the same metadata in a documented format (with an API error-code structure). It should work with the compiler-generated metadata and should not require debug views to be present.
Compile-time control: a compiler option or H-spec keyword (e.g. REFLECT(*YES | *NO | *PUBLICONLY)) so developers decide which variables expose metadata. Default *NO to avoid increasing object size or exposing information unintentionally.
Use cases
- Generic serializers/deserializers (JSON, XML, CSV) that map data structures to documents without hand-written field lists or
DATA-INTO/DATA-GEN workarounds.
Generic logging and tracing: print any variable with its name and type.
Data validation and mapping frameworks (e.g. REST API request/response validation and mapping)
Dynamic SQL parameter binding using actual variable types.
Modernization tools and debuggers that need type information at runtime.
Business justification
IBM i shops with large RPG code bases need to integrate with modern services (REST, JSON, messaging) and to build generic tools. Today this requires repetitive boilerplate or maintenance of statically written variable metadata. Native reflection reduces development cost and defects and brings RPG closer to the capabilities of other platforms that attract new developers.
Security and compatibility considerations
- Metadata exposure is opt-in per module/program.
Backward compatible; existing programs are unaffected.
Access through the API respects normal object authority (e.g. *USE to the program/service program).
Workaround today: Debug APIs, listing parsing or manually maintained metadata, all unsupported for production or not maintainable.
I support
I like that idea, but you are already able to do "introspection" by creating a custom handler procedure for the DATA-GEN opcode.
This will give a good introspection, which you can of course emit to the target variable (probably a VARCHAR). A handler of this kind would be quite easy to write.
But of course, this doesn't help with a passed generic pointer - in this case you only can use system APIs to get more information about the variable behind that handler.
This sounds cool! While I doubt anyone would take the challenge to implement generic parameters (that most variations of this suggestion requires) or equivalent code duplication (like in zig), I think it could be useful to get a limited functionality similar to what %size does, but getting full variable metadata. %size (and other BIFs) only work in the scope they are in, but allow to adapt to type changes without changing magic constants around the code (if you need them), so getting one that exposes every detail about a declared variable sounds like enormous convenience and it's already partially covered by aforementioned %size, %len, %elem and so on, so why not.