Example 1: Record introspection and modification

This example describes a RECORD variable with the reflection API.

records.4gl source:

IMPORT reflect

PRIVATE FUNCTION _check_record(val reflect.Value) RETURNS ()
    IF val.getType().getKind() != "RECORD" THEN
        DISPLAY "ERROR: Expecting a RECORD"
        EXIT PROGRAM 1
    END IF
END FUNCTION

PRIVATE FUNCTION _show(rec reflect.Value, spaces STRING) RETURNS ()
    DEFINE tp reflect.Type
    DEFINE fv reflect.Value
    DEFINE fc, x SMALLINT
    DEFINE s STRING
    CALL _check_record(rec)
    LET tp = rec.getType()
    LET fc = tp.getFieldCount()
    FOR x = 1 TO fc
        LET fv = rec.getField(x)
        CASE fv.getType().getKind()
        WHEN "PRIMITIVE"
            LET s = fv.toString()
            DISPLAY spaces, tp.getFieldName(x), " : ", NVL(s,"NULL")
        WHEN "RECORD"
            DISPLAY spaces, tp.getFieldName(x), ":"
            CALL _show(fv, spaces||" ")
        WHEN "ARRAY"
            DISPLAY spaces, tp.getFieldName(x), ": array"
        WHEN "DICTIONARY"
            DISPLAY spaces, tp.getFieldName(x), ": dictionary"
        END CASE
    END FOR

END FUNCTION

PUBLIC FUNCTION show(rec reflect.Value) RETURNS ()
    CALL _show(rec, " ")
END FUNCTION

PUBLIC FUNCTION set_undef(rec reflect.Value) RETURNS ()
    DEFINE tp reflect.Type
    DEFINE fv reflect.Value
    DEFINE fc, x SMALLINT
    CALL _check_record(rec)
    LET tp = rec.getType()
    LET fc = tp.getFieldCount()
    FOR x = 1 TO fc
        LET fv = rec.getField(x)
        CASE fv.getType().getKind()
        WHEN "PRIMITIVE"
            CASE
            WHEN fv.getType().toString() MATCHES "*CHAR*"
                CALL fv.set( reflect.Value.copyOf("<undefined>") )
            END CASE
        WHEN "RECORD"
            CALL set_undef(fv)
        END CASE
    END FOR
END FUNCTION
main.4gl source:
IMPORT reflect
IMPORT FGL records

DEFINE rec_cust RECORD
           pkey INTEGER,
           name VARCHAR(40),
           creation DATETIME YEAR TO SECOND,
           address RECORD
               street VARCHAR(200),
               pcode VARCHAR(5),
               city VARCHAR(50)
           END RECORD
       END RECORD
    
TYPE Circle RECORD
           x FLOAT,
           y FLOAT,
           r FLOAT
       END RECORD
DEFINE circle1 Circle

MAIN

    CALL records.set_undef( reflect.Value.valueOf(rec_cust) )
    LET rec_cust.pkey = 101 
    LET rec_cust.name = "Mike Fitzpatrick"
    LET rec_cust.address.pcode = "7236"
    LET rec_cust.address.city = "Redrock"
    LET rec_cust.creation = CURRENT
    DISPLAY "rec_cust:"
    CALL records.show( reflect.Value.valueOf(rec_cust) )
    
    LET circle1.x = 9834.23
    LET circle1.y = 1334.56
    LET circle1.r = 4.50
    DISPLAY "circle1:"
    CALL records.show( reflect.Value.valueOf(circle1) )

END MAIN
Output:
rec_cust:
 pkey : 101
 name : Mike Fitzpatrick
 creation : 2020-07-30 11:54:37
 address:
  street : <undefined>
  pcode : 7236
  city : Redrock
circle1:
 x : 9834.23
 y : 1334.56
 r : 4.5