How to Use Typed Arrays versus Packed Arrays in gdext-nim

In gdext-nim, use generic Array[T] (typed arrays) for flexible collections of mixed Godot Variants, and Packed*Array types for maximum-performance storage of homogeneous primitives.

The gdext-nim framework provides two distinct container families for managing collections in Godot 4. Understanding when to use typed arrays versus packed arrays in gdext is essential for writing performant Nim game code. This guide examines the implementation details found in the godot-nim/gdext-nim repository to help you choose the right container for your data.

Core Architecture: Variant Arrays vs Packed Arrays

Typed Arrays (Array[T])

In src/gdext/arraytools.nim, the generic Array[T] type wraps Godot's native Variant array. Despite the compile-time generic T, the runtime storage remains a list of Godot Variants. This design allows heterogeneous content but adds per-element overhead.

The implementation uses two helper procedures for safe casting between typed and generic forms:

proc wild[T](self: Array[T]): Array[Variant] =
  when T is Variant: self 
  else: cast[ptr Array[Variant]](addr self)[]

proc specified[T](self: Array[Variant]; Type: typedesc[T]): Array[T] =
  when T is Variant: self 
  else: cast[ptr Array[T]](addr self)[]

Packed Arrays

Located in src/gdext/gen/ (e.g., gdpackedstringarray.nim, gdpackedint32array.nim, gdpackedvector3array.nim), these types store homogeneous primitives in contiguous C-style memory without Variant overhead. They expose the same API methods (size, pushBack, clear) but call Godot's native packed-array methods directly.

Creating and Converting Typed Arrays

Storing Custom Objects

Use Array[T] when you need type safety at compile time while maintaining compatibility with Godot's Variant system:

import gdext

type MyNode = ref object of Node
registerClass(MyNode)

let node = MyNode.new()
var objs = newArray[MyNode]()      # typed array with T = MyNode

objs.pushBack(node)                # stored internally as Variant

echo objs.size                     # → 1

echo objs[0].className            # → "MyNode"

Converting Between Typed and Variant Arrays

You can implicitly convert typed arrays to generic Variant arrays using the wild cast, and return to the original type using specified:

var intArr = newArray[int](3)
intArr[0] = 10
intArr[1] = 20
intArr[2] = 30

let varArr: Array[Variant] = intArr   # implicit conversion via wild

let back: Array[int] = varArr.specified(int)  # cast back via specified

echo back[1]   # → 20

Working with Packed Arrays

Basic Packed String Operations

For string collections requiring maximum efficiency, use PackedStringArray defined in src/gdext/gen/gdpackedstringarray.nim:

import gdext

var pStr = newPackedStringArray()
pStr.pushBack("hello")
pStr.pushBack("world")
echo pStr.size                     # → 2

echo pStr[0]                       # → "hello"

Converting Typed Arrays to Packed Arrays

When you need to transform a flexible Array[Variant] into an efficient packed format, use the constructor defined in src/gdext/gen/gdpackedstringarrayconstr.nim:

var varArr = newArray[Variant]()
varArr.pushBack("one")
varArr.pushBack("two")
varArr.pushBack("three")

let packed = newPackedStringArray(varArr)  # constructor from Variant array

echo packed.size          # → 3

echo packed[2]            # → "three"

This conversion attempts to cast each Variant element to the packed type and fails at runtime if a value cannot be converted.

Integration with Godot APIs

Certain Godot methods explicitly require packed arrays for low-level data operations. For example, mesh construction requires PackedVector3Array for vertex data:

import gdext

var verts = newPackedVector3Array()
verts.pushBack(Vector3(0, 0, 0))
verts.pushBack(Vector3(1, 0, 0))
verts.pushBack(Vector3(0, 1, 0))

let mesh = ArrayMesh.new()
mesh.addSurfaceFromArrays(
  PrimitiveType.Triangles,
  [ArrayMesh.ArrayFormat.Vertex, verts]  # packed array passed directly

)

When to Choose Which Container

  • Use Array[T] when you need heterogeneous content (different object types), compatibility with Godot APIs accepting generic Variants, or storage of user-defined objects implementing toVariant/fromVariant.

  • Use Packed*Array when processing large homogeneous datasets (mesh vertices, audio samples, string tables), interacting with low-level Godot methods requiring packed buffers, or when memory efficiency and cache locality are critical.

Summary

  • Typed arrays (Array[T]) in src/gdext/arraytools.nim provide compile-time type safety over Godot's underlying Variant array storage, using wild and specified casts for type conversion.
  • Packed arrays (PackedStringArray, PackedByteArray, etc.) in src/gdext/gen/ store homogeneous primitives in contiguous memory without Variant overhead.
  • Convert between the two using constructors like newPackedStringArray(from: Array[Variant]) found in src/gdext/gen/gdpackedstringarrayconstr.nim.
  • Choose typed arrays for flexibility and packed arrays for performance-critical primitive data.

Frequently Asked Questions

Can I store custom Nim objects in a PackedArray?

No. Packed arrays only store homogeneous native primitives like String, int32, float64, or Vector3. Custom classes and heterogeneous collections require Array[T] (typed arrays), which store elements as Godot Variants internally according to the implementation in src/gdext/arraytools.nim.

How do I convert between Array[int] and PackedInt32Array?

Use the constructor pattern found in src/gdext/gen/gdpackedint32arrayconstr.nim. First convert your typed array to Array[Variant] using the implicit wild cast, then pass it to newPackedInt32Array(varArr). Note that this conversion copies data and validates that each Variant contains a compatible integer type.

Why does Array[T] still use Variant storage internally?

Godot's engine API expects Array to be a single Variant type capable of holding any value. The generic T in gdext-nim is strictly a compile-time hint for type safety; at runtime, the array remains a Godot Variant array as implemented in src/gdext/arraytools.nim. This ensures seamless interoperability with Godot's dynamic scripting system.

Which array type should I use for large datasets like mesh vertices?

Always use the appropriate Packed*Array type (e.g., PackedVector3Array for vertices) when working with large homogeneous datasets. According to src/gdext/gen/gdpackedvector3array.nim, these arrays avoid the per-element Variant overhead, providing contiguous memory layout that Godot's rendering and physics systems can process efficiently.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →