5

I wish i could do some reflection using RPGLe. By reflection, I mean : 'The process or mechanism of determining the capabilities of an object at run-time.'

Imagine you have this datastructure :

 D DS_Format       DS                  Qualified Based(pDS_Format)
 D  Type                         20I 0 Inz(1)
 D  Label                        50A   Inz('myLabel')
 D  Description                5000A   Inz('myDescription')        

With a reflection api, I could do this :

Reflection_ListSubfields(DS_Format); 

=> return this array : { 'Type', 'Label', 'Description' }

And then, I could do :

Reflection_GetSubfield(DS_Format : 'Label'); => return 'myLabel'

I wish i could do this too :

Reflection_GetSubfieldType(DS_Format : 'Label'); => return 'A'
Reflection_GetSubfieldLength(DS_Format : 'Label'); => return 50
Reflection_GetSubfieldPrecision(DS_Format : 'Type'); => return 0

With this, I expect I could do something like this (with some little work) :

SerializeXml(DS_Format); //I build xml with one line of code !

And get :

<DS_Format>
    <Type>1</Type>
    <Label>myLabel</Label>
    <Description>myDescription</Description>
</DS_Format>

And conversely with DeserializeXml(myXml);

Reflection would help me to build really cool apis. Is there any way ?

Charles Martin
  • 420
  • 4
  • 12
  • Surprisingly there's no cozzi's tuesday tip for this. :) Reflection is an OO concept so you won't be seeing it in a procedural language like RPG. You're better off using something like Java. – Ben Thurley Oct 30 '13 at 15:00
  • There is nothing like that available in RPGLE. – Benny Hill Oct 30 '13 at 15:05

3 Answers3

3

I have been contemplating some of these concepts, and may have a work around. (I don't have time at the moment to write a full answer & flesh out the details yet, but waited you to see there is some hope ;-) although some may consider it a cheat.)

The basic concept is this: IF you define a table with the desired format if your days structure, enabling the DS to be externally defined, then with embedded SQL you could DESCRIBE the table or query SYSCOLUMNS to get your field definitions, preferably in procedures.

Granted, this is not the same thing as refection, but could accomplish much the same. And one would probably only do this in limited circumstances. I'm sure others will point out a variety of issues, but the point here is that it is possible.

WarrenT
  • 4,502
  • 19
  • 27
2

I'm wondering if the debug APIs could help get at least some of the behavior you are asking for...

http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/topic/apis/debug1.htm

One of the included functions is Dump Module Variables (QteDumpModuleVariables) API

Of course, you're job would have to be in debug mode to use these APIs...

Charles
  • 21,637
  • 1
  • 20
  • 44
2

The following is a very simple implementation of WarrenT's idea.

create table ds_format
(
   Type        numeric(20, 0),
   Label       char(50),
   Description char(5000)
);

Constant for the SQL description area:

D SQL_NUM         C                   99

Implementation of Reflection_ListSubfields in an SQLRPGLE module that returns an array of field names:

P Reflection_ListSubfields...                         
P                 B                                
 *                                                 
D                 PI            80A   Dim(SQL_NUM) 
D  name                         30A   Const
 *                                                 
D tableName       S                   Like(name)   
D i               S              3S 0 Inz          
D fieldList       S             80A   Dim(SQL_NUM) 
 /free                                             
    EXEC SQL include SQLDA;                        

    // retrieve description of the table                                           
    tableName = name;                              
    EXEC SQL describe table :tableName into :sqlda;

    // loop over all fields and
    // retrieve the name                                                   
    for i = 1 to SQLD;                             
       SQLVAR = SQL_VAR(i);                        
       fieldList(i) = SQLNAME;                     
    endfor;                                        

    return fieldList;
 /end-free           
P                 E  

Now a very rough implementation of Reflection_GetSubfield that returns the value as a string:

P Reflection_GetSubfield...                                   
P                 B                                        
 *                                                         
D                 PI         32000A   Varying              
D  dataStruct                     *   Const                
D  name                         30A   Const
D  fieldName                    80A   Const                
 *                                                         
D tableName       S                   Like(name)           
D i               S              3S 0 Inz                  
D start           S              6S 0 Inz(1)               
D length          S              6S 0 Inz(1)               
D p_str           S               *                        
D str             S          32000A   Based(p_str)         
D value           S          32000A   Varying              
 /free                                                 
    EXEC SQL include SQLDA;                        

    // retrieve description of the table                                           
    tableName = name;                                  
    EXEC SQL describe table :tableName into :sqlda;    

    // loop over all fields
    for i = 1 to SQLD;                                 
       SQLVAR = SQL_VAR(i);                            

       length = SQLLEN;                                

       // Zoned decimal?
       if SQLTYPE = 489;                               
          length = SQLLEN / 256;                       
       endif;                                          

       // field found?                                                       
       if SQLNAME = fieldName;                         
          leave;                                       
       endif;

       start += length;                             
    endfor;                                            

    p_str = dataStruct;                                 

    // retrieve value from our string                                                
    value = %trim(%subst(str: start: length));  

    return value;                               
 /end-free                                      
P                 E                             

I guess with this information it is relatively easy to implement the other three procedures.

cloose
  • 916
  • 5
  • 18
  • 2
    The general question problem comes from RPG being compiled. Like most compiled languages, variable names become meaningless and are replaced with addresses and offsets. But for external descriptions such as SQL tables, things change. This example using SQL is one way to get it done. It might be simplified by using a call to the [**Retrieve Database File Description (QDBRTVFD) API**](http://pic.dhe.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/apis/qdbrtvfd.htm) and referencing the field array at Qddffldx in the Format Definition Header (Qdb_Qddfmt). – user2338816 Apr 30 '14 at 14:13