Arrays¶
An array is one name for an ordered field of values. D/BASIC preserves BASIC's wonderfully direct subscripting while making whole-array work visible enough for a compiler and a tiny runtime to do it well.
Declare an array¶
Each dimension can name only an upper bound or an explicit lower TO upper pair. OPTION BASE supplies an omitted lower bound:
D/BASIC supports up to eight dimensions. Bounds and subscripts are converted to INTEGER.
Read and write elements¶
An element acts like a variable of the array's element type. Assignment conversion happens before storage.
Stay inside the declared bounds. D/BASIC checks rather than allowing an out-of-range index to wander into unrelated memory.
Ask for the bounds¶
LBOUND and UBOUND report the live bounds. Pass a second argument for a particular dimension:
FOR Row% = LBOUND(Board%, 1) TO UBOUND(Board%, 1)
FOR Column% = LBOUND(Board%, 2) TO UBOUND(Board%, 2)
PRINT Board%(Row%, Column%);
NEXT Column%
PRINT
NEXT Row%
Without the dimension argument, dimension 1 is used.
Resize and erase¶
REDIM gives a dynamic array a new shape:
REDIM PRESERVE keeps the overlapping values while changing the allowed bounds:
REDIM PRESERVE does not apply to arrays of TYPE records. Use ordinary REDIM for an atomic replacement, or copy record elements explicitly when preserving them is part of your algorithm.
ERASE releases an array binding and leaves it null:
That null state matters to the whole-array verbs below. It is a real state, not an empty rank-one array whose upper bound happens to be -1.
Whole-array parameters¶
Empty parentheses identify a whole-array carrier:
DECLARE FUNCTION Sum& (Values() AS INTEGER)
FUNCTION Sum& (Values() AS INTEGER)
DIM Total AS LONG
FOR I% = LBOUND(Values) TO UBOUND(Values)
Total = Total + Values(I%)
NEXT I%
Sum& = Total
END FUNCTION
The callee sees the live bounds. A whole-array parameter is not an element, a slice, or an untyped bag.
The three whole-array verbs¶
| Intent | Syntax | What moves | Allocation shape |
|---|---|---|---|
| copy | ARRAYCOPY Source() TO Destination() |
every element into an independent binding | destination becomes a fresh copy |
| fill | ARRAYFILL Destination(), Value |
one converted value to every element | same element type, rank, and bounds; atomic replacement |
| swap | ARRAYSWAP A(), B() |
only the two bindings | no element copy and no new array allocation |
All operands shown with () must be bare whole arrays. A(), not A, A(I), Object.A(), or a subrange.
The whole-array verbs accept arrays whose elements are numeric scalars, variable STRINGs, or CLASS references. They do not accept arrays of TYPE records. Copy, initialize, or exchange record elements explicitly so the record-value boundary remains visible.
ARRAYCOPY: make an independent array¶
DIM Draft%(1 TO 4)
DIM Published%()
Draft%(1) = 10
Draft%(2) = 20
ARRAYCOPY Draft%() TO Published%()
Draft%(1) = 99
PRINT Published%(1) ' 10: this is a separate binding
Use a copy when both versions must remain independently mutable.
ARRAYFILL: one meaning, every element NEW¶
The value is converted exactly as one element assignment would be:
Fill keeps the destination's element type, rank, and bounds. It is transactional: if the operation refuses partway through preparation, the old binding remains authoritative rather than exposing a half-filled array. This can require one temporary array-sized allocation.
Filling an ERASEd/null destination refuses because there is no shape to fill.
Why it is a language verb¶
This loop is readable:
But ARRAYFILL Plane%(), -1 says more. It promises that element order is irrelevant, exposes the operation to the optimizer, lowers to one DBC instruction, and lets a runtime use the most appropriate memory route while retaining atomic semantics.
ARRAYSWAP: change ownership, not elements NEW¶
DIM Front%(1 TO 1000)
DIM Back%(1 TO 1000)
' Draw from Front while preparing the next state in Back.
ARRAYFILL Back%(), 0
' ...modify Back()...
ARRAYSWAP Front%(), Back%()
ARRAYSWAP exchanges the bindings. Contents, lower and upper bounds, and rank travel with each binding. No elements are copied, allocated, retained, or released.
The arrays must have the same element type. When both are live, they must have equal rank; their individual bounds may differ:
DIM Live%(1 TO 3)
DIM Held%(0 TO 1)
ARRAYSWAP Live%(), Held%()
PRINT LBOUND(Live%); UBOUND(Live%) ' 0 1
A null binding is legal and swaps as null. That makes a fast “take this array and leave nothing” handoff possible:
DIM Ready%(1 TO 3)
DIM Taken%(1 TO 3)
ERASE Taken%
ARRAYSWAP Ready%(), Taken%()
' Taken now owns the former Ready array; Ready is null.
The memory trick to remember¶
Fill changes the values. Swap changes the name that owns them. If you find yourself copying a large back buffer merely to make it current, you probably meant ARRAYSWAP.
Classic scalar SWAP¶
SWAP exchanges two scalar or compatible record locations:
It is intentionally different from ARRAYSWAP, whose operands are whole array bindings.
Arrays of records and objects¶
TYPE Point
X AS INTEGER
Y AS INTEGER
END TYPE
DIM Path(0 TO 31) AS Point
DIM Buttons(0 TO 7) AS WorksButton
Record elements are inline values. Class elements are object references initialized to NOTHING; assigning an object stores a counted reference. The difference is explored in Records & Objects.
These arrays are ordinary containers, but the three whole-array verbs above apply only to numeric, variable-string, and class-reference arrays—not to TYPE record arrays.
Patterns worth teaching¶
A ring without mysterious memory¶
A table driven by bounds¶
Do not repeat 1 TO 100 in every loop. Let the array report its own truth.
Front/back state¶
Prepare in Back(), then ARRAYSWAP Front(), Back(). Readers either see the old complete state or the new complete state, never your construction site.
Quick rules¶
- Bounds are inclusive.
- The default lower bound is
0unless one module-levelOPTION BASE 1says otherwise. - Use
LBOUNDandUBOUNDin reusable procedures. - Use
ERASEto release the binding. - Use
ARRAYCOPYfor independence,ARRAYFILLfor a uniform state, andARRAYSWAPfor an ownership exchange. - Use those three verbs only with numeric, variable-string, or class-reference element types.
- Whole-array parentheses are not decoration; they distinguish the binding from an element.
Next: Records & Objects →