redefines

Declaring a record variable that redefines another

You can declare a record variable that redefines an area of memory that has already been assigned to another record variable. For example, you can write a loop that reads one data area after another from a serial file, even though the structure of the retrieved data is different from one retrieval to the next, as in the following example:
Record RecordA type SerialRecord
   { fileName = "myFile"  }
   record_type char(1);
   field1 char(20); 
end 

Record RecordB type BasicRecord
   10 record_type char(1);
   10 field2 bigint;
   10 field3 decimal(7);
   10 field4 char(8); 
end

Program ProgramX type basicProgram
   myRecordA RecordA;
   myRecordB RecordB {redefines = myRecordA};
   
   function main();
     get next myRecordA;
     while (myRecordA not endOfFile)
       if (myRecordA.record_type == "A")
         myFunction01(myRecordA.field1);
       else
         myFunction02(myRecordB.field2, myRecordB.field3, myRecordB.field4);
       end
       get next myRecordA;
     end
   end 
end
Within the loop, the function performs the following actions:
  1. Checks the first field in the input record for a code that identifies the structure of the rest of the data.
  2. Processes the other fields in the retrieved data by using either the input record or a second, basic record. The second record refers to the same area of memory as the input record but is structured differently.

To declare one record variable as a redefinition of another, you use the redefines property. The property accepts the name of another record variable. This property is only available in a record variable declaration, not in a Record part definition.

The original and overlay record can be any types of structured record, with the following restrictions:
  • The records must be in the same scope. For example, if you declare the first record as a field of a containing record, you must also declare the record that redefines the first record as a field in the same containing record:
    Record StructuredRecordA
       10 x INT;
    end
    
    Record StructuredRecordB
      10 y INT;
    end
    
    Record TestRecord
      myRec1 StructuredRecordA;
      myRec2 StructuredRecordB { redefines=myRec1};
    end
    Similarly, if you declare one record in a library but outside of a function, you must also declare the other in the same library and also outside of a function.
  • The overlay record must have the same length or be shorter than the original record. This restriction prevents your code from accessing an area in the overlay record that is not in the area of memory being redefined.
  • Some record stereotypes can require hidden bytes. For more information, check the documentation for the individual record type.

The properties you assign to the original record do not affect the overlay record; only the memory area is redefined.

You cannot use an overlay record for I/O.

Declaring a field that redefines another from the same record

You can apply the redefines property to a field under the following circumstances only:
  • The redefining field and the redefined field must be in the same record.
  • The record must be structured.
  • Both fields must be at the same level and have the same parent.
  • The length of the redefining field must not be greater than the length of the redefined field.
The two fields may have different types, but only the type of the redefined record is retained if you pass or initialize the record. The following example illustrates this idea:
Record exampleRecord1
   10 a INT;
      20 aa INT;
      20 ab CHAR(4) { redefines = a.aa };
   10 b CHAR(4) { redefines = a };
end

If you pass a variable based on exampleRecord1 in a call statement, the data of the redefined area is converted as if it were an INT and not a CHAR(4). If you initialize a.ab (for example, with a set empty statement), the data of the redefined area will be set to binary zeros and not blanks.

The field doing the redefinition must come immediately after the field being redefined, ignoring child fields and redefinitions. The following two examples are both valid:
Record exampleRecord2
   10 a int;
      20 x int;
   10 b char(4) { redefines = a };
      20 z char(4);
   10 c char(4) { redefines = a };
end
A field defined as an array may not be redefined. If a field is an array because one of its parents is an array, it may be redefined.
Record exampleRecord3
   10 a int[2];
   10 b char(2) { redefines = a };  // Illegal because a is an array
end

Record exampleRecord4
   10 a bigint;
   10 b char(1)[8] { redefines = a };  // Legal
end

Record exampleRecord5
   10 top char(4)[3];
      20 a int;
      20 b smallint { redefines = a };  // Legal even though a is an array
end

Record exampleRecord6
   10 top char(12)[5];
      20 middle char(4)[3];
         30 a int;
         30 b smallint { redefines = a };  // Legal even though a is an array
end
The following detailed example uses field redefinition to normalize US dates (month first) with European dates (day first). In the RecC record definition, usBillingDate and euroBillingDate are indented beneath billingDate, though all three have the same level number (10). The indentation is a visual cue to make the point that all three fields occupy the same space, despite having the same level numbers. The redefining field always overwrites the redefined field.
package com.companyb.customer;

Record RecC type basicRecord
   10 dateFormat SMALLINT;
   10 billingDate CHAR(8);
      10 usBillingDate CHAR(8) {redefines=billingDate};
         20 month CHAR(2);
         20 day CHAR(2);
         20 year CHAR(4);   
      10 euroBillingDate CHAR(8) {redefines=billingDate};
         20 day CHAR(2);
         20 month CHAR(2);
         20 year CHAR(4);      
   10 deliveryDate CHAR(8);
      10 usDeliveryDate CHAR(8) {redefines=deliveryDate};
         20 month CHAR(2);
         20 day CHAR(2);
         20 year CHAR(4);      
      10 euroDeliveryDate CHAR(8) {redefines=deliveryDate};
         20 day CHAR(2);
         20 month CHAR(2);
         20 year CHAR(4);      
End


program RedefinesExample type BasicProgram ( 
   inDateFormat SMALLINT,
   inDeliveryMonth CHAR(2),
   inDeliveryDay CHAR(2),
   inDeliveryYear CHAR(4),
   inBillingMonth CHAR(2),
   inBillingDay CHAR(2),
   inBillingYear CHAR(4))
   {alias="REDXMP3"}

   // aRec is a structured record whose billingDate and deliveryDate items
   // are each redefined by two other items with substructure,
   // whose level is the same, and whose parent is the same   
   aRec RecC;
   
   const USDateFormat SMALLINT=1;
   const EURODateFormat SMALLINT=2;
   
   function main()
      aRec.dateFormat = inDateFormat;
      // If date to be in US format
      if ( inDateFormat == USDateFormat )
         usBillingDate.month = inBillingMonth;
         usBillingDate.day = inBillingDay;
         usBillingDate.year = inBillingYear;
         usDeliveryDate.month = inDeliveryMonth;
         usDeliveryDate.day = inDeliveryDay;
         usDeliveryDate.year = inDeliveryYear;
      else // Date must be in European format
         euroBillingDate.month = inBillingMonth;
         euroBillingDate.day = inBillingDay;
         euroBillingDate.year = inBillingYear;
         euroDeliveryDate.month = inDeliveryMonth;
         euroDeliveryDate.day = inDeliveryDay;
         euroDeliveryDate.year = inDeliveryYear;
      end
   end
   
end

Feedback