Skip to content

Variables, DIM & memory

A variable is a name with three promises: a type, a place to live, and a lifetime. DIM makes those promises visible. That matters on every machine, but it matters especially when the same program may run with megabytes of memory on one host and kilobytes on another.

Start with the ordinary form

DIM Score AS INTEGER
DIM Distance#
DIM CustomerName AS STRING
DIM Price AS DECIMAL

Score = 12
Distance# = 41.75
CustomerName = "MIRA"
Price = 19.9500@

You may put compatible declarations on one line:

DIM Left AS INTEGER, Top AS INTEGER
DIM Width%, Height%

A suffix is part of the declaration. An AS clause is usually easier to read in public APIs; suffixes remain excellent for short local calculations.

DIM always declares a binding. What storage it creates depends on the type and shape:

Declaration Initial meaning
DIM Count AS LONG one numeric value, initially 0
DIM Label AS STRING one variable string, initially empty
DIM Point AS PointType one inline TYPE value with initialized fields
DIM Button AS WorksButton one class reference, initially NOTHING
DIM Samples%(0 TO 255) one array binding plus 256 initialized elements
DIM Samples%() a null dynamic-array binding with no shape yet

This is the distinction that prevents a great deal of confusion:

DIM declares a class reference. NEW constructs the object it may refer to.

DIM Save AS WorksButton

IF Save IS NOTHING THEN PRINT "NOT CONSTRUCTED"
Save = NEW WorksButton("save", "Save")

Constructors therefore run because of NEW, not because a class name appeared after AS. Assigning NOTHING releases that variable's strong reference.

Explicit declarations beat accidental storage

D/BASIC accepts compact listings in which a scalar first appears at assignment. Its type then follows the suffix, DEF* range, or default numeric rule. That is useful for transferred code, but a substantial new program should declare state that survives more than a few lines.

DEFINT I-N

DIM ItemCount AS INTEGER
DIM RunningTotal AS LONG
DIM ReportTitle AS STRING

An undeclared numeric name is otherwise SINGLE. DIM Count is not shorthand for DIM Count AS INTEGER.

Scope answers “who can see it?”

Form Visible from Lifetime
top-level DIM top-level module code program or application session
top-level DIM SHARED module code and its procedures program or application session
procedure DIM that invocation until the invocation returns
procedure STATIC that procedure retained between invocations
class instance field methods and allowed users of that object until its owning object is destroyed
class STATIC field the class-qualified name program or application session
DIM SHARED RunCount AS LONG

SUB Visit ()
  STATIC Previous AS LONG
  RunCount = RunCount + 1
  PRINT "NOW"; RunCount; " PREVIOUS"; Previous
  Previous = RunCount
END SUB

Keep state in the narrowest useful scope. A local is easier to reason about than a shared value; an instance field is easier to compose than an unrelated global.

Arrays allocate a shape

Bounds are inclusive:

DIM Week%(1 TO 7)
DIM Board%(0 TO 7, 0 TO 7)
DIM Samples#()

REDIM Samples#(0 TO 255)

The empty parentheses in DIM Samples#() reserve only the binding. REDIM later creates or replaces its shape. REDIM PRESERVE retains values in the overlap between the old and new bounds:

REDIM PRESERVE Samples#(0 TO 511)

An allocation or conversion refusal leaves the previous live binding authoritative; D/BASIC does not publish a half-resized array. ERASE releases the complete binding and returns it to the null state:

ERASE Samples#

Arrays covers dimensions, bounds, ARRAYCOPY, ARRAYFILL, and zero-copy ARRAYSWAP in detail.

Records live inline; objects have identity

TYPE Coordinate
  X AS INTEGER
  Y AS INTEGER
END TYPE

DIM Here AS Coordinate
DIM There AS Coordinate

Here.X = 12
There = Here             ' independent record copy

A TYPE value is its fields. Assignment copies it. A CLASS value is a counted reference to an object with identity. Assignment makes another strong reference to that same object:

DIM First AS WorksButton
DIM AlsoFirst AS WorksButton

First = NEW WorksButton("go", "Go")
AlsoFirst = First
PRINT First IS AlsoFirst        ' -1

That value/reference distinction also controls parameter passing; see BYREF and BYVAL.

Strings are managed values

A variable STRING is not a fixed character array and does not expose a pointer. Assignment, concatenation, slicing, and replacement produce governed string values, and the runtime releases unreferenced storage deterministically.

DIM Given AS STRING
DIM Family AS STRING
DIM DisplayName AS STRING

Given = "Ada"
Family = "Lovelace"
DisplayName = Given + " " + Family

See Strings & Text before slicing user-entered UTF-8: core string positions count bytes, while UI text services preserve committed text and composition as semantic events.

Memory failure is an ordinary governed outcome

D/BASIC has no source-visible address, allocator token, or pointer arithmetic. The emitted DBC declares its static and runtime requirements, and each runner admits only what it can serve honestly. Dynamic work can still exceed a live capacity: a large REDIM, concatenation, object graph, or decoded resource may refuse rather than corrupt another value.

On the first 6502 target, that ordinary model begins with a 512 KiB logical program-memory pool. The 6502 large-memory chapter explains hidden banking, paging, memory tiers, and Intent acceleration.

Practical habits:

  1. Allocate arrays to the bounds the algorithm actually needs.
  2. Reuse long-lived buffers when that makes ownership clearer.
  3. Use ARRAYSWAP for front/back ownership instead of copying large arrays.
  4. Release arrays with ERASE, objects with NOTHING, and host sessions with their explicit close operation.
  5. Keep cleanup reachable from both success and refusal paths.

A complete storage example

DEFINT A-Z

DIM SHARED Visits AS LONG

SUB Summarize (Values() AS INTEGER)
  DIM Total AS LONG
  FOR I = LBOUND(Values) TO UBOUND(Values)
    Total = Total + Values(I)
  NEXT I
  Visits = Visits + 1
  PRINT "TOTAL"; Total; " VISIT"; Visits
END SUB

DIM Readings(1 TO 4) AS INTEGER
ARRAYFILL Readings(), 5
CALL Summarize(Readings())
ERASE Readings
END

The example has module lifetime, invocation lifetime, one explicit array allocation, one whole-array mutation, and one explicit release. No address is part of the program's meaning.


Next: Strings & Text →