Quick answer: Use arrays ([], array_push, array_length) for almost everything. ds_list is legacy: slower, leaks if not destroyed, and the API is less ergonomic.
An older GameMaker project uses ds_list everywhere. A profiler comparison shows array_* operations beat ds_list_* by 2–3x for typical operations. Memory leaks track to forgotten ds_list_destroy calls. Time to migrate.
The Trade-Offs
ds_list:
- Pre-2.3 GameMaker primitive.
- Manually managed: ds_list_create + ds_list_destroy.
- Leaks if you forget destroy.
- Slower than array operations in modern GameMaker.
Arrays:
- Native, GC’d.
- Rich function family (array_push, array_pop, array_filter, array_map, ...).
- Dynamic length without manual reallocate.
- Faster on most operations.
Migration Cheat Sheet
// ds_list_create → []
var list = [];
// ds_list_add(list, val) → array_push(arr, val)
array_push(list, "hello");
// ds_list_find_value(list, i) → arr[i]
var v = list[0];
// ds_list_size(list) → array_length(arr)
var n = array_length(list);
// ds_list_delete(list, i) → array_delete(arr, i, 1)
array_delete(list, 0, 1);
// ds_list_destroy → not needed; just stop referencing
Higher-Order Functions
var nums = [1, 2, 3, 4, 5];
var evens = array_filter(nums, function(v) { return v % 2 == 0; });
var squared = array_map(nums, function(v) { return v * v; });
var total = array_reduce(nums, function(acc, v) { return acc + v; }, 0);
ds_list has no equivalents. Migration not only gains performance but unlocks functional-style code.
Tracking ds_list Leaks
Use ds_get_active_lists (debug build) to count live ds_lists. If the count grows monotonically, you have leaks. Hunt them down by adding show_debug_message at each ds_list_create call site.
When to Keep ds_*
ds_map is still useful for string-keyed dictionaries when struct typing isn’t practical (e.g., dynamic key sets from user input). ds_queue, ds_stack, ds_priority can still be cleaner than rolling your own with arrays for specific algorithms. But for general lists, prefer arrays.
Verifying
Profile a benchmark before and after migration. Use get_timer() to measure microseconds of array vs ds_list operations on the same workload. Arrays should be measurably faster. Memreport should not show ds_list count climbing in stable scenes.
“Modern GameMaker arrays are first-class. ds_list is legacy — faster to migrate than to keep maintaining.”
When porting older GMS1.x or 2.2 projects, replacing ds_list with arrays is usually the biggest free perf win available.