Reference / Usage

Once a dynamic structure variable has been declared and bound to a structure definition it is ready to be referenced or used. The general idea and syntax are similar to that for regular fixed structure members, with the main difference being that the members are unknown to the compiler, and instead have to be resolved at runtime. 

There are two semantic variations, each with slightly different syntax:

Simple Indirect

The syntax here is identical to that for a traditional structure, e.g.

ds.id = "Dynamo"     ! member name is "id"

ds.amount = 12.34    ! member name is "amount"

 

Although the above syntax is the same as for traditional structures, the semantics are different. Instead of using the compiled definition of the member, the run-time interpreter looks up the member by its textual name —e.g. "id" or "amount"—in the dynstruct definition bound to the dynstruct variable (ds in this example) to get the member’s data type and offset within the structure.

This scheme is probably most useful for repurposing code originally written to work on traditional structures and conforms to the "duck typing" paradigm.

Indirect Deferred

In this variation, the specified member name is a string variable whose contents contain the actual member name, which is then treated as in the Simple Indirect scheme described above. The syntax uses a dot followed by the "at" sign, i.e. ".@",hopefully reinforcing the idea that the target member requires two steps to resolve.

ds.@id = "Dynamo"    ! member name is value of id var

ds.@amount = 12.34   ! member name is value of amount var

 

The indirect deferred method is more flexible than the simple indirect in that it doesn’t require you to have code written in advance with any knowledge of the structure members. But most likely you would want to use a string array to hold the field names, rather than individual scalar variables. For example:

map1 ds,dynstruct

dimx fnames$(0),s,64,auto_extend  ! array of potential member names

<load fnames$() array from some external source>

<define the dynamic structure and bind it to the variable ds>

for i = 1 to .extent(fnames$())   ! now cycle thru the members

    ds.@fnames$(i) = <value>

next i

 

Array Dynstruct Members

Array dynstruct members present a potential syntactic ambiguity in that it isn’t obvious from the source code whether ds.@fname$(i) refers to a scalar member whose name is the value of fname$(i), or an array member whose name is the value of fname$, in which case the subscript (i) applies to the dynstruct array member.

To avoid this ambiguity, the compiler will treat fname$(i) as a normal array variable (as we would expect), i.e. as the container holding the name of the scalar dynstruct member. The only way to access an array member using the indirect deferred syntax is to use an array variable to hold the member name, which will result in two sets of subscripts, one for the array holding the member name, and one for the target dynstruct member array. For example, consider the structure:

Defstruct ST_FOO

    map2 sku,s,10

    map2 price(3),f

Endstruct

 

If the structure is defined and bound to a dynstruct variable ds, and fname$(1) = "sku" and fname$(2) = "price(", then:

? ds.@fname$(1)    ! refers to sku member

? ds.@fname$(2)(1) ! refers to ds.price(1)

? ds.@fname$(2)(2) ! refers to ds.price(2)

? ds.@fname$(2)(3) ! refers to ds.price(3)

 

Currently A-Shell BASIC has no variable syntax with adjacent pairs of parenthesized terms, so there is no ambiguity for the compiler in recognizing that fname$(2)(3) can be compiled as two separate components: fname$(2), resolved at runtime as "price(", and (3), resolved separately at runtime and then combined with "price(" to get the member name "price(3)".

Note that when referring to the name of a dynstruct array member, it must contain at least the open parenthesis, i.e. "price(" rather than simply "price".