# How to Work with Properties and Ivar Layout in mulle‑objc‑runtime

> Master properties and ivar layout in mulle‑objc‑runtime with our guide. Understand ivar descriptors, property descriptors, and accessor implementations for zero-overhead direct memory access and full introspection.

- Repository: [mulle-objc/mulle-objc-runtime](https://github.com/mulle-objc/mulle-objc-runtime)
- Tags: how-to-guide
- Published: 2026-03-07

---

**In mulle‑objc‑runtime, properties compile into three linked structures—an ivar descriptor storing the byte offset, a property descriptor linking to that ivar and storing accessor method IDs, and the accessor implementations themselves—enabling zero‑overhead direct memory access while maintaining full introspection capabilities.**

Working with properties and ivar layout in the mulle‑objc‑runtime requires understanding how the system decomposes Objective‑C properties into runtime metadata. Unlike traditional runtimes that hide these details, mulle‑objc exposes explicit structures in [`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h) and [`src/mulle-objc-property.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-property.h) that map every property to its backing storage and accessor methods. This architecture allows developers to enumerate instance variables, map properties to their backing ivars, and perform direct memory access using calculated offsets.

## Understanding the Three‑Part Property System

In mulle‑objc, a property is not a single entity but a compile‑time description expanded into three tightly‑coupled pieces: the ivar descriptor, the property descriptor, and the accessor methods.

### Ivar Descriptors and Layout

The **ivar descriptor** is defined in [`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h) (lines 49‑66) as `struct _mulle_objc_ivar`. It contains the instance variable’s name, type‑encoding, unique ivar‑id, and crucially, the **byte offset** inside an object’s memory block. The offset is calculated when the class is registered and remains constant for the lifetime of the program, enabling stable direct memory access.

### Property Descriptors and Metadata

The **property descriptor** lives in [`src/mulle-objc-property.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-property.h) (lines 16‑27) as `struct _mulle_objc_property`. It stores the property name, type‑encoding (including attributes like `readonly` or `copy`), a unique property‑id, and the `ivarid` field that links the property to its backing storage. It also caches the getter and setter method‑ids in the `getter` and `setter` fields for fast dispatch.

### Accessor Method Linkage

When a property is synthesized (`@synthesize`) or declared `@dynamic`, the compiler generates or expects accessor implementations. The property descriptor stores the method IDs for these accessors (`getter`, `setter`, `adder`, `remover`), allowing the runtime to connect property metadata to executable code without repeated string lookups.

## Walking Ivars and Properties at Runtime

The runtime provides walker functions to enumerate ivars and properties, supporting both direct class inspection and inheritance traversal.

### Enumerating Instance Variables

To walk all ivars including those inherited from superclasses, use `_mulle_objc_infraclass_walk_ivars` with the `MULLE_OBJC_INHERIT_SUPERCLASS` flag. This function is declared in [`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h) and invokes a callback for each `struct _mulle_objc_ivar`.

```c
#include <mulle-objc-runtime/mulle-objc-runtime.h>
#include <stdio.h>

static mulle_objc_walkcommand_t
print_ivar(struct _mulle_objc_infraclass *infra,
           struct _mulle_objc_ivar *ivar,
           void *info)
{
    printf("Ivar: %-12s  type: %-20s  offset: %d\n",
           mulle_objc_ivar_get_name(ivar),
           mulle_objc_ivar_get_signature(ivar),
           mulle_objc_ivar_get_offset(ivar));
    return MULLE_OBJC_WALK_CONTINUE;
}

int main(void)
{
    struct _mulle_objc_universe      *universe;
    struct _mulle_objc_infraclass    *cls;

    universe = mulle_objc_global_get_defaultuniverse();
    cls = mulle_objc_universe_lookup_infraclass_nofail(
            universe,
            mulle_objc_classid_from_string("Person"));
    if (!cls) return 1;

    _mulle_objc_infraclass_walk_ivars(cls,
        MULLE_OBJC_INHERIT_SUPERCLASS,
        print_ivar, NULL);
    return 0;
}

```

Key helper functions include `mulle_objc_ivar_get_name()`, `mulle_objc_ivar_get_signature()`, and `mulle_objc_ivar_get_offset()`, all defined in [`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h).

### Looking Up a Single Ivar

For direct lookup without walking, use `mulle_objc_infraclass_search_ivar`, which searches the class’s ivar list by identifier.

```c
struct _mulle_objc_ivar *ivar;
ivar = mulle_objc_infraclass_search_ivar(cls,
                                        mulle_objc_ivarid_from_string("age"));
if (ivar)
{
    int   offset = mulle_objc_ivar_get_offset(ivar);
    char *name   = mulle_objc_ivar_get_name(ivar);
    char *type   = mulle_objc_ivar_get_signature(ivar);
    printf("Found ivar %s (%s) at offset %d\n", name, type, offset);
}

```

### Enumerating Properties

Properties are enumerated similarly using `_mulle_objc_infraclass_walk_properties`, implemented in [`src/mulle-objc-propertylist.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-propertylist.c) (lines 46‑70). The walker invokes a callback receiving `struct _mulle_objc_property` and the host class.

```c
static mulle_objc_walkcommand_t
print_property(struct _mulle_objc_property *property,
              struct _mulle_objc_infraclass *infra,
              void *userinfo)
{
    printf("Property: %-12s  type: %-20s  bits: 0x%04x\n",
           mulle_objc_property_get_name(property),
           mulle_objc_property_get_signature(property),
           mulle_objc_property_get_bits(property));
    return MULLE_OBJC_WALK_CONTINUE;
}

/* Usage */
_mulle_objc_infraclass_walk_properties(cls,
                                      0,
                                      print_property,
                                      NULL);

```

## Mapping Properties to Ivars

To understand how properties and ivar layout interact, map a property descriptor back to its backing ivar. The property’s `ivarid` field (defined in [`src/mulle-objc-property.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-property.h), lines 18‑20) stores the unique identifier of the associated instance variable.

```c
struct _mulle_objc_property *prop;
struct _mulle_objc_ivar    *ivar;

prop = _mulle_objc_infraclass_search_property(
          cls, mulle_objc_propertyid_from_string("name"));
if (!prop) return;

ivar = mulle_objc_class_search_ivar(&cls->base, prop->ivarid);

printf("Property signature : %s\n", 
       mulle_objc_property_get_signature(prop));
printf("Backing ivar signature : %s\n", 
       ivar ? mulle_objc_ivar_get_signature(ivar) : "none");

```

This linkage confirms that when you work with properties and ivar layout in mulle‑objc, the property metadata directly references the ivar’s byte offset, allowing the runtime to synthesize accessors that read from or write to the correct memory location.

## Direct Ivar Access Using Layout Offsets

For high‑performance scenarios, bypass accessor methods and access ivars directly using the offset stored in the ivar descriptor. This technique respects the ivar layout while eliminating message‑send overhead.

```c
/* Assume 'person' is an instance and 'ivar' is the descriptor for 'age' */
int offset = mulle_objc_ivar_get_offset(ivar);   /* e.g., 8 */
int *age_ptr = (int *)((char *)person + offset);
*age_ptr = 42;   /* Direct memory write */

```

The offset is calculated once during class registration and remains immutable, providing C‑level performance while maintaining type safety through the ivar’s signature encoding. This pattern is particularly useful when you need to work with properties and ivar layout in performance‑critical loops where even cached method lookups are too expensive.

## Key Source Files

When working with properties and ivar layout, reference these definitive source locations in the mulle‑objc‑runtime repository:

- **[`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h)** – Defines `struct _mulle_objc_ivar` and accessor helpers like `mulle_objc_ivar_get_offset()`.
- **[`src/mulle-objc-property.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-property.h)** – Defines `struct _mulle_objc_property` including the `ivarid` linkage field and attribute bits.
- **[`src/mulle-objc-propertylist.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-propertylist.c)** – Implements `_mulle_objc_infraclass_walk_properties()` and search helpers (lines 46‑70).
- **[`src/mulle-objc-class.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-class.h)** – Provides `mulle_objc_class_search_ivar()` for cross‑referencing properties to ivars.
- **[`book/chapter3-ivar-system.md`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/book/chapter3-ivar-system.md)** – Narrative documentation of ivar layout and direct‑access patterns.
- **[`book/chapter5-property-system.md`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/book/chapter5-property-system.md)** – Overview of property metadata, synthesis, and introspection.

These files provide the complete implementation of how properties are tied to ivars, how the runtime stores layout offsets, and how you can query or manipulate them at runtime.

## Summary

- **Three‑part architecture**: Properties decompose into ivar descriptors (layout offsets), property descriptors (metadata and linkage), and accessor method IDs.
- **Ivar layout stability**: Offsets are computed at class registration and stored in `struct _mulle_objc_ivar`, enabling direct memory access via `mulle_objc_ivar_get_offset()`.
- **Property‑to‑ivar mapping**: The `ivarid` field in `struct _mulle_objc_property` links properties to their backing storage, resolvable via `mulle_objc_class_search_ivar()`.
- **Runtime inspection**: Use `_mulle_objc_infraclass_walk_ivars()` with `MULLE_OBJC_INHERIT_SUPERCLASS` to traverse inherited ivars, and `_mulle_objc_infraclass_walk_properties()` for property enumeration.
- **Zero‑overhead access**: Direct ivar manipulation using calculated offsets bypasses message dispatch while respecting the runtime’s type encodings.

## Frequently Asked Questions

### How does mulle‑objc‑runtime store the byte offset for instance variables?

The runtime stores the byte offset inside `struct _mulle_objc_ivar`, defined in [`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h). The offset is calculated when the class is registered and remains constant for the lifetime of the program. You retrieve it using `mulle_objc_ivar_get_offset()`, which returns the byte distance from the object’s start address to the ivar’s location.

### What is the relationship between a property and its backing ivar in mulle‑objc?

A property links to its backing ivar through the `ivarid` field in `struct _mulle_objc_property` (defined in [`src/mulle-objc-property.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-property.h)). When a property is synthesized, the compiler creates an ivar entry and populates the property descriptor’s `ivarid` with that ivar’s unique identifier. At runtime, you can resolve this connection by calling `mulle_objc_class_search_ivar()` with the property’s `ivarid`.

### Can I access instance variables directly without using property accessors?

Yes. You can bypass accessor methods by using the offset stored in the ivar descriptor. Call `mulle_objc_ivar_get_offset()` to get the byte offset, then calculate the memory address by adding that offset to the object pointer. This technique provides C‑level performance while maintaining type safety through the ivar’s signature encoding.

### Where are the property and ivar walk functions implemented?

The ivar walk function `_mulle_objc_infraclass_walk_ivars()` is declared in [`src/mulle-objc-ivar.h`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-ivar.h) and supports inheritance flags like `MULLE_OBJC_INHERIT_SUPERCLASS`. The property walk function `_mulle_objc_infraclass_walk_properties()` is implemented in [`src/mulle-objc-propertylist.c`](https://github.com/mulle-objc/mulle-objc-runtime/blob/main/src/mulle-objc-propertylist.c) (lines 46‑70), with search helpers like `_mulle_objc_infraclass_search_property()` available for direct lookups by property ID.