Inheritance

A struct may extend one base struct, inheriting its storage and accessible behavior while adding its own fields and members.

Declaring a base struct

Place the base type after :. Xenon uses single struct inheritance: a derived struct has at most one base struct.

struct Entity
{
    public int Id;
}

struct Enemy : Entity
{
    public int Health;
}

Enemy contains both Id and Health. Public base members are available through the derived value; private members remain internal to the struct that declares them.

Layout

The base struct storage begins at offset zero in the derived layout. Base fields are physically part of every derived value, followed by storage introduced by the derived struct according to the target ABI layout.

Inheritance and allocation

The complete derived value may live on the stack, inline inside another value or in heap memory. Inheritance affects its layout, not where it must be allocated.

Base constructors

A derived constructor selects a base constructor with : base(arguments). Base construction completes before the derived constructor body runs.

struct Entity
{
    public int Id;

    public Entity(int id)
    {
        Id = id;
    }
}

struct Enemy : Entity
{
    public int Health;

    public Enemy(int id, int health) : base(id)
    {
        Health = health;
    }
}

When a derived constructor omits an explicit base call, Xenon selects an available parameterless base constructor.

See constructor initialization order for the sequence of base construction, derived field initializers and the derived body.

Pointer and reference conversions

A derived pointer or reference converts implicitly to the corresponding base pointer or reference. The conversion preserves the identity of the original derived object.

Enemy enemy = Enemy(7, 100);

Entity& entity = enemy;
Entity* pointer = &enemy;

int id = entity.Id;

The reverse base-to-derived conversion is not implicit.

Value conversions and object slicing

Xenon does not implicitly convert a derived struct value to a base struct value. A by-value assignment that would keep only the base fields is rejected instead of silently discarding the derived part.

Enemy enemy = Enemy(7, 100);

Entity copy = enemy; // error: no implicit derived-to-base value conversion
No accidental object slicing

This prevents the C++-style slicing case. If Vector3 extends Vector2, assigning a Vector3 directly to a Vector2 value does not silently discard Z; the program fails to compile.

Vector3 vector = Vector3(1.0f, 2.0f, 3.0f);

Vector2 vector2 = vector; // error: cannot implicitly convert Vector3 to Vector2

Use a base reference or pointer when the same object should be viewed through its base contract:

Entity& baseView = enemy;
Entity* basePointer = &enemy;

int id = baseView.Id;

Derived-only fields are not accessible through the statically typed base view, but they remain stored in the original object. Converting the view does not copy, truncate or reallocate that object, and virtual calls still dispatch to the runtime derived implementation.

To create a genuinely separate base value, construct one explicitly from the fields that should be retained. That is an ordinary new value, not an implicit conversion:

Entity copy = Entity(enemy.Id);

Destructor order

Destruction proceeds from the most-derived struct toward its bases. The derived destructor body runs first, after which Xenon invokes the base destructor automatically exactly once.