Arrays, collections & dictionaries
Choose a container by how you need to find, order and change its values.
Three different access models#
| Container | Use it for | Index / key |
|---|---|---|
| Array | A typed set with a declared shape | Declared lower and upper bounds |
| Collection | An ordered group that grows | One-based positions and optional keys |
| Dictionary | Lookup by a meaningful key | Check Exists before Item when absence is expected |
Collection and Dictionary items must be scalar values, not controls or class instances. Use typed object arrays for those references. A control’s Items or a Recordset is not interchangeable with a plain array. The object defines both its mutation operations and its indexing rules.
Read the actual array bounds#
Public Function SumReadings() As Long
Dim readings(-1 To 1) As Long
Dim index As Long
Dim total As Long
readings(-1) = 10
readings(0) = 20
readings(1) = 30
For index = LBound(readings) To UBound(readings)
total = total + readings(index)
Next index
SumReadings = total
End FunctionThis array runs from -1 through 1. The total is 60. A loop that assumes the first element is zero would skip a valid value.
Grow a dynamic array deliberately#
Public Function GrowReadings() As Long
Dim readings() As Long
ReDim readings(0 To 1)
readings(0) = 4
readings(1) = 5
ReDim Preserve readings(0 To 2)
readings(2) = 6
GrowReadings = readings(0) + readings(1) + readings(2)
End FunctionThe example expands the upper bound and keeps the existing 4 and 5 with Preserve, then adds 6. Its result is 15. Declare the array with empty parentheses before ReDim.
Pass resizable storage to a resizing procedure#
An array declared with bounds, such as Dim readings(0 To 1) As Long, is fixed-size even if a later ReDim would request the same bounds. A typed array parameter is ByRef; declaring it with empty parentheses does not turn a fixed caller array into a dynamic one. From build 834, Check reports MCB2102 at a fixed argument when the callee resizes that parameter with ReDim, ReDim Preserve or whole-array assignment. Forwarding the parameter to another resizing procedure counts too.
Public Sub FillReadings(ByRef readings() As Long)
ReDim readings(0 To 2)
readings(0) = 20
readings(1) = 30
readings(2) = 40
End Sub
Public Function ReadingsFromProcedure() As Long
Dim readings() As Long
FillReadings readings
ReadingsFromProcedure = readings(0) + readings(1) + readings(2)
End FunctionThe caller declares empty parentheses. FillReadings allocates all three elements before the caller reads them; the result is 90. If the caller needs elements before making the call, it must ReDim first. A fixed array remains valid for a routine that only reads/writes elements or uses Erase to clear them. The new check is not a ban on passing fixed arrays.
Reproduce the Check error, then repair it#
Use a disposable copy of LanguageWorkbench.
- Run Check and Test; all nine tests should pass.
- In ReadingsFromProcedure only, replace
Dim readings() As LongwithDim readings(0 To 1) As Long. - Run Check. Expect MCB2102 on
FillReadings readings, explaining that the fixed-size argument is passed to a resizing parameter. - Restore the declaration with empty parentheses. Do not remove the callee’s ReDim: it initializes the data.
- Repeat Check and Test. Confirm the result is 90 and the bounds test passes.
Error 10 remains a runtime guard where static analysis cannot establish the storage contract. See fixed versus locked arrays; catching error 10 is not a substitute for correcting the declaration.
Keep order and identity separate#
Public Function CollectionCount() As Long
Dim names As Collection
Set names = New Collection
names.Add "Ada", "first"
names.Add "Grace", "second"
names.Remove "first"
CollectionCount = names.Count
End FunctionThe two entries have keys “first” and “second”. Removing “first” leaves one item. A list position can change after removal, while an application record’s identity should remain stable.
Check a key before reading it#
Public Function LookupName() As String
Dim names As Dictionary
Set names = New Dictionary
names.Add "lead", "Ada"
If names.Exists("lead") Then
LookupName = CStr(names.Item("lead"))
Else
LookupName = "Unknown"
End If
End FunctionThe known key returns “Ada”; an absent key follows the explicit fallback. Convert the stored Variant only after you know it is present and compatible.
Mutate the control’s collection, not its reference#
ListBox, ComboBox, ImageCombo and ListView expose read-only Items references. Clear or add through that collection; do not assign a string to the Items reference in BASIC. The Inspector’s one-item-per-line field supplies the initial list. Menu, ContextMenu, ToolBar and TabStrip retain their separate String Items contract.
For named control arrays, shared handlers and Me.Controls, use the control-array guide. For typed object arrays and Preserve, follow the class-array lesson. For live selection and associated IDs, follow ChoiceBinding. For full signatures, consult collection services.
20f4bfed6b · Build manifestSources & maintenance
Original web explanation, reviewed against these repository sources. API tables and example files follow the implementation.
docs/manual/21-language-reference.mddocs/manual/11-language-toolkit.mdsite/examples/LanguageWorkbench/Main.bassrc/McBasic.Compiler/ArrayResizeAnalysis.cssrc/McBasic.Compiler/Binder.cssrc/McBasic.Compiler/CallArguments.cssrc/McBasic.Runtime/BasicRuntime.cssite/examples/LanguageWorkbench/LanguageTests.bas