Updated October 2017
DEFSTRUCT <structname>
{optional MAP1 <varname1>}
MAP2 <fieldname1>
...
MAPn <fieldnameN>
ENDSTRUCT
A DEFSTRUCT ... ENDSTRUCT block may be used to assign a type name to a set of MAP statements and then use that as if it was a standard variable type. This is similar to the combination of typedef and struct in the C language and is useful for many data standardization and encapsulation scenarios, including handling multiple copies of a record layout, or passing complex data as parameters.
To define a structure, use the DEFSTRUCT and ENDSTRUCT keywords to enclose a set of MAP statements. For example:
DEFSTRUCT ST'PHONE
MAP2 DESCR,S,20 ! e.g. Front Office, Accounts Payable, etc.
MAP2 TYPE,S,6 ! e.g. cell, bus, home, pager
MAP2 XNUM
MAP3 COUNTRYCODE,S,3
MAP3 AREA,S,3
MAP3 NUMBER,S,10
ENDSTRUCT
DEFSTRUCT ST_CUS
MAP1 CUSTREC
MAP2 ID,S,6
MAP2 NAME,S,30
MAP2 PHNUM(5), ST'PHONE ! array of ST'PHONE structures
MAP2 BALANCE,F
ENDSTRUCT
MAP1 SALE, ST_CUS ! SALE is an instance of structure ST_CUS
MAP1 PROSPECT(10), ST_CUS ! PROSPECT() is an array of struct ST_CUS
DIMX CLIENTS(N),ST_CUS ! Dynamic array of structures
MAP1 PH$, ST'PHONE ! PH$ is an instance of struct ST'PHONE
...
PH$ = FN'GETPHONENUM$(SALE,"cell") ! retrieve cell # from customer SALE
FUNCTION FN'GETPHONENUM$(cus as ST_CUS, type$ as S6) as ST'PHONE
map1 locals
map2 i,f
! locate phone number by matching type
for i = 1 to 5
if cus.PHNUM.TYPE(i) = type$ then
FN'GETPHONENUM$ = cus.PHNUM(i)
endif
next i
ENDIF
The above example illustrates defining two structures, ST_PHONE and ST_CUS. (Structures have the same naming flexibility as other variables, but it seems like a useful convention to prefix their formal names with ST_ to avoid confusion with variable names.) The ST_CUS structure contains an array of ST_PHONE structures, illustrating that they can be nested. The example then defines an instance of the ST_CUS structure called SALE, a fixed array of instances call PROSPECT(), a dynamic array called CLIENTS(), and an instance of the ST_PHONE structure called PH$.
Note that the MAP1 CUSTREC line within the DEFSTRUCT ST_CUS definition is not exactly a field within the structure, but instead creates an additional set of traditional (non-structure) map statements for the contents of the structure. In other words, without even declaring an instance of the ST_CUS structure, the map statements within it can still be accessed in the traditional way. This makes it easy to convert traditional sets of MAP statements used for record layouts into structures, without requiring any changes to existing code. Without the MAP1 element, the structure can only be used by declaring a mapped instance of it.
The following shows the equivalent (fully expanded) form of MAP1 SALE, ST_CUS :
MAP1 SALE
MAP2 SALE.ID,S,6
MAP2 SALE.NAME,S,30
MAP2 SALE.PHNUM(5)
MAP3 SALE.PHNUM.DESCR,S,20
MAP3 SALE.PHNUM.TYPE,S,6
MAP3 SALE.PHNUM.XNUM
MAP4 SALE.PHNUM.COUNTRYCODE,S,3
MAP4 SALE.PHNUM.AREA,S,3
MAP4 SALE.PHNUM.NUMBER,S,10
Note the use of the period to separate the names of structure instances from the fields in the structure.
Also note that the syntax for accessing individual members of dynamic arrays of structures is different; see Dynamic Array of Structures for details.
Warning: initial values for individual mapped fields within a structure definition are allowed for mapped instances of the structure, but not for DIMX; see Dynamic Array of Structures. Prior to compiler edit 521, such initial values led to runtime errors; after that the compiler just ignored the initial values. See the A-Shell forum discussion "MAP initializers in DEFSTRUCT."
So, for example, you might read the structure from a disk file and then print out the ID field as follows:
READ #CH, SALE
PRINT "Customer ID = ";SALE.ID
Defined structure names may be used similarly to the unformatted type X, and passed to functions and procedures. In the example above, the function FN'GETPHONENUM$() takes a ST_CUS structure as an argument, and returns a ST'PHONE structure.
Defined structure names may end in $, but the $ is dropped when referencing the individual fields. For example:
defstruct ST_CUS
map2 id,s,10
map2 name$,s,30
endstruct
map1 cus$,ST_CUS ! structure names may end in $
map1 tmpcus,ST_CUS ! (or not)
! use the $ when referring to the structure as a whole
tmpcus = cus$
! drop the $ from structure name when referring to individual fields
cus.id = "A12345"
! field names may end in $, just like any other variable
cus.name$ = "Agamemnon"
(Note that because function names must contain a $ suffix if the function returns an S or X value, and since structures are essentially a special variation of the X type, any function returning a structure must have a $ on the end of the name.)
The formal parameter "cus as ST_CUS" essentially creates a set of local map statements which are identical to the ones shown above for SALE, except with "SALE." replaced by "cus." Otherwise, in terms of parameter passing, the "cus as ST_CUS" parameter is equivalent to "cus as X246". (Previously, this is how you had to pass the structure, and then you had to repeat the MAP2-MAP9 levels of the structure map statements within the Function. So the new method doesn't exactly add any new capability, but it makes using structures and especially passing them between routines much cleaner and easier.
One way to help clarify the effect of structure definitions is to compile with the /L switch, in which case the expanded forms of the structures will display in the LSX file.
See Also
• A-Shell forum discussion "DEFSTRUCT newbie question."
History
2017 July, A-Shell 6.4.1552/6.5.1603, compiler edit 828: add ability to include an initial MAP1 within the DEFSTRUCT; see comments.
2010 July, A-Shell 5.1.1187, Compiler edit 456: reserved words are now allowed for field names within a DEFSTRUCT. For example:
DEFSTRUCT ST_TIMEDATE
MAP2 TIME,B,4
MAP2 DATE,B,4
ENDSTRUCT
Normally TIME and DATE would be disallowed since they are reserved words, but since they get appended to the structure instance name before really being used, there is no conflict here.
2008 September, A-Shell 5.1.1124: Initial values and overlays are now supported within DEFSTRUCT / ENDSTRUCT.
2008 September, A-Shell 5.1.1123: DEFSTRUCT now allows upper and lower case (or mixed case) formal structure names, and STATIC and PRIVATE instances of structures now allowed. Note that DIMX does not support structures.