Ark
Unsafe API

Unsafe API

So far, we used the type-safe, generic API of Ark throughout. However, there may be use cases where component types are not known at compile-time, like serialization and de-serializations. For these cases, Ark offers an unsafe, ID-based API. It is accessible via ecs.World.Unsafe.

Component IDs

Internally, each component type is mapped to an ecs.ID. We don’t see it in the generic API, but we can use it for more flexibility in the ID-based API. IDs can be obtained by the function ecs.ComponentID. If a component is not yet registered, it gets registered upon first use.

1world := ecs.NewWorld()
2
3posID := ecs.ComponentID[Position](&world)
4velID := ecs.ComponentID[Velocity](&world)
5
6_, _ = posID, velID

Creating entities

Entities are created with ecs.Unsafe.NewEntity, giving the desired component IDs:

1entity := world.Unsafe().NewEntity(posID, velID)
2_ = entity

Filters and queries

Filters and queries work similar to the generic API, but also component IDs instead of generics:

1filter := ecs.NewFilter(&world, posID, velID)
2
3query := filter.Query()
4for query.Next() {
5	pos := (*Position)(query.Get(posID))
6	vel := (*Velocity)(query.Get(velID))
7	pos.X += vel.X
8	pos.Y += vel.Y
9}

Important

Note the type casts! These are required because ecs.Query.Get returns an unsafe.Pointer to the underlying component storage. Extra care should be taken here, because this is a common source of bugs and the cast is not checked for the correct type.

Component access

Components of entities can be accessed outside queries using ecs.Unsafe.Get/ecs.Unsafe.Has:

1entity := world.Unsafe().NewEntity(posID, velID)
2
3pos := (*Position)(world.Unsafe().Get(entity, posID))
4_ = pos

Important

Again, note the type cast! See above for details.

Component operations

Components can be added and removed using methods of ecs.Unsafe:

1entity := world.NewEntity()
2
3world.Unsafe().Add(entity, posID, velID)
4world.Unsafe().Remove(entity, posID, velID)

Limitations

Besides not being type-safe (i.e. you can cast to anything without an immediate error), the unsafe API has a few limitations:

  • It is slower than the type-safe API.
  • Newly added components can’t be initialized directly.
    ecs.Unsafe.Get must be used for initialization.
  • There are currently no batch operations provided for the unsafe API.