Array members

Array members of the dynstruct present a special problem in that the syntax to reference an array is necessarily distinct from the syntax to reference a scalar. One has a parenthesized list of subscripts at the end, the other does not. Worse, there’s no current way to avoid writing different template statements for each array with a different number of dimensions. For example, the following statements show the indirect deferred syntax for a scalar member and for a series of array members of 1, 2, and 3 dimensions:

ds.fnames$(i)          ! scalar member

ds.fnames$(i)(x)       ! 1-dimension array member

ds.fnames$(i)(x,y)     ! 2-dimension array member

ds.fnames$(i)(x,y,z)   ! 3-dimension array member

 

The compiler has no way to enforce agreement between the subscripts specified at compile time and the number actually needed for the target member at run-time, because it doesn’t know which dynstruct member  fnames$(i) will evaluate to. The runtime system can detect the most common error, where you use the first syntax above for an array member, i.e. you forget to supply any subscripts for the array member. That will produce an undefined member error; see Dynstruct Error Handling. But it cannot detect the case where the target array needs 3 subscripts, but you only supplied 2, or vice versa. That might cause a stack overflow or underflow, but it might just cause another part of the current expression (waiting its turn on the stack) to be misused as an array subscript, which in turn will almost certainly lead to another runtime error like illegal syntax code or undefined function.

One take-away is to avoid using arrays in dynstructs. If that’s not possible, the other is that is you must then be careful to add logic like the following to detect the various array cases and to use the appropriate template statements depending on the dimensionality of each array member.

! sample retrieval/display using indirect deferred syntax

! (with logic to avoid printing members of type X or with sub-members,

! and logic to handle array members)

for i = 1 to fields

    if (flddefs(i).vartyp and VARTYP_MASK) = VARTYP_X then

        repeat                              ! skip X vars

    elseif (i < fields) and flddefs(i+1).pos = flddefs(i).pos then

        repeat                              ! skip vars with sub-layouts

    elseif flddefs(i).subs = 0 then         ! scalar member

        ? dstest.@fnames$(i)    ! print only non-X, non-multilevel
    else

        switch flddefs(i).subs

            case 1                          ! 1 dimension array

                for x = 1 to flddefs(i).subext(1)

                    ? dstest.@fnames$(i)(x)

                next x

                exit

            case 2                          ! 2 dimension array

                for x = 1 to flddefs(i).subext(1)

                    for y = 1 to flddefs(i).subext(2)

                        ? dstest.@fnames$(i)(x,y)

                    next y

                next x

                exit

 

            case 3                          ! 3 dimension array

                for x = 1 to flddefs(i).subext(1)

                    for y = 1 to flddefs(i).subext(2)

                        for z = 1 to flddefs(i).subext(3)

                            ? dstest.@fnames$(i)(x,y,z)

                        next z

                    next y

                next x

                exit

         endswitch

    endif

next i