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
endWithin the loop, the function performs the following
actions:
- Checks the first field in the input record for a code that identifies the structure of the rest of the data.
- 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:
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.Record StructuredRecordA 10 x INT; end Record StructuredRecordB 10 y INT; end Record TestRecord myRec1 StructuredRecordA; myRec2 StructuredRecordB { redefines=myRec1}; end - 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 };
endIf 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 };
endA 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
endThe 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