# How to Interact with the Core mulle-objc Runtime from MulleObjC Code

> Discover how to interact with the core mulle-objc runtime directly from MulleObjC code. Access zero-overhead inline wrappers for efficient runtime manipulation.

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

---

**Include the [`mulle-objc.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc.h) umbrella header to access zero-overhead inline wrappers like `MulleObjCObjectPerformSelector*` and `MulleObjCObjectGetBOOL` for direct runtime manipulation.**

The **mulle-objc** runtime is a lightweight, high-performance engine powering the MulleObjC language. Unlike traditional Objective-C runtimes that hide internals behind complex abstraction layers, mulle-objc exposes its core functionality directly through simple C headers. When you need to interact with the core mulle-objc runtime from MulleObjC code, you work with `static inline` functions that compile down to raw runtime calls with no linking overhead.

## Accessing Runtime Functions via the Umbrella Header

### Include the Runtime Header

All runtime entry points flow through [`src/mulle-objc.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/mulle-objc.h). This umbrella header exports the complete API surface, from low-level dispatch functions to high-level convenience wrappers.

```c
#include "mulle-objc.h"

```

### Available Runtime Capabilities

Including this header grants access to four primary categories of runtime interaction:

- **Message sending helpers** – `MulleObjCObjectPerformSelector0`, `MulleObjCObjectPerformSelector1`, and variants up to `MulleObjCObjectPerformSelector2` for dispatching methods with object arguments, plus primitive-specific variants like `MulleObjCObjectPerformSelectorDoubleArgument`.
- **Class and selector introspection** – `MulleObjCClassGetID`, `MulleObjCClassImplementsSelector`, and `MulleObjCLookupClassByNameUTF8String` for runtime type discovery.
- **Object utilities** – `MulleObjCObjectGetClass`, `MulleObjCInstanceSetClass`, and `MulleObjCInstanceConstantify` for direct instance manipulation.
- **Primitive accessors** – `MulleObjCObjectGetBOOL`, `MulleObjCObjectSetInt`, and related functions that handle boxing/unboxing automatically.

All wrappers live in [`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h) and remain `static inline`, ensuring the compiler optimizes away the abstraction layer entirely.

## Common Runtime Operations

### Dynamic Class and Selector Lookup

Before sending messages dynamically, obtain the `Class` and `SEL` identifiers through UTF-8 string lookups. These functions search the runtime's class and selector tables without requiring compile-time knowledge of the types.

```c
Class   MyClass = MulleObjCLookupClassByNameUTF8String("MyClass");
SEL     sel     = MulleObjCCreateSelectorUTF8String("doSomething:");

```

`MulleObjCLookupClassByNameUTF8String` queries the global class table, while `MulleObjCCreateSelectorUTF8String` registers the selector in the selector table if absent.

### Sending Messages with Arguments

The runtime provides variadic-style wrappers for message sending. For simple no-argument selectors:

```c
id result = MulleObjCObjectPerformSelector0(anObject, sel);

```

For two object arguments:

```c
id result = MulleObjCObjectPerformSelector2(anObject, sel, arg1, arg2);

```

When passing primitive values like doubles or integers, use specialized wrappers that handle the meta-ABI automatically:

```c
SEL sel = MulleObjCCreateSelectorUTF8String("setScale:");
MulleObjCObjectPerformSelectorDoubleArgument(obj, sel, 1.5);

```

### Runtime Introspection and Mutation

Check whether a class implements a method directly (excluding inherited methods) using `MulleObjCClassImplementsSelector`:

```c
if (MulleObjCClassImplementsSelector(MyClass, sel))
    NSLog(@"MyClass implements %@", MulleObjCSelectorUTF8String(sel));

```

For advanced scenarios like test harnesses or proxy implementations, mutate an instance's class identity directly:

```c
MulleObjCInstanceSetClass(anObject, MyClass);

```

This operation, declared near line 75 in [`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h), modifies the object's isa pointer immediately.

## Architectural Layers

### High-Level Wrappers vs. Low-Level Runtime API

The codebase maintains a strict separation between convenience and control:

- **High-level wrappers** (`MulleObjCObjectPerformSelector*`, `MulleObjCObjectGetBOOL`) suit everyday code needing primitive value handling or fixed-argument dispatch. These inline functions reside in [`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h) and call into the runtime internally.

- **Low-level runtime functions** (`mulle_objc_object_call`, `mulle_objc_class_search_method`) provide raw access to method table walks, caching strategies, and fast-path optimizations. These are declared in [`mulle-objc-runtime/mulle-objc-runtime.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc-runtime/mulle-objc-runtime.h) and useful for custom method resolution or metaprogramming.

Both layers remain accessible simultaneously; the compiler inlines the wrappers, so you pay no penalty for choosing the ergonomic API.

### Key Source Files for Runtime Interaction

Understanding the repository structure helps navigate the runtime surface:

- **[`src/mulle-objc.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/mulle-objc.h)** – The primary umbrella header that re-exports all runtime capabilities and convenience wrappers.
- **[`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h)** – Contains the static inline implementations of `MulleObjCObjectPerformSelector*` and primitive accessors (lines 33-80).
- **[`mulle-objc-runtime/mulle-objc-runtime.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc-runtime/mulle-objc-runtime.h)** – Exposes the underlying `mulle_objc_*` functions handling dispatch, class tables, and selector tables.
- **[`src/class/NSObject.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/class/NSObject.h)** – Demonstrates how the runtime hooks integrate with root class definitions.
- **[`src/protocol/NSObjectProtocol.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/protocol/NSObjectProtocol.h)** – Defines protocol metadata used during method lookup.

## Practical Code Examples

### Example 1 – Dispatch with Primitive Arguments

```c
#import "mulle-objc.h"

void sendDoubleMessage(id obj)
{
    SEL sel = MulleObjCCreateSelectorUTF8String("setScale:");
    // Wrapper handles meta-ABI for double argument automatically
    MulleObjCObjectPerformSelectorDoubleArgument(obj, sel, 1.5);
}

```

*Implementation located in [`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h), lines 73-80.*

### Example 2 – Verify Class-Specific Method Implementation

```c
#import "mulle-objc.h"

BOOL classImplementsFoo(Class cls)
{
    SEL sel = @selector(foo:);
    return MulleObjCClassImplementsSelector(cls, sel);
}

```

*Implementation located in [`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h), lines 33-55.*

### Example 3 – Runtime Class Lookup and Invocation

```c
#import "mulle-objc.h"

void invokePrint(id obj)
{
    Class  Printer = MulleObjCLookupClassByNameUTF8String("Printer");
    SEL    selPrint = MulleObjCCreateSelectorUTF8String("print");
    if (Printer && MulleObjCClassImplementsSelector(Printer, selPrint))
    {
        // Equivalent to [obj print];
        MulleObjCObjectPerformSelector0(obj, selPrint);
    }
}

```

### Example 4 – Advanced Instance Reclassification

```c
#import "mulle-objc.h"

void reclassifyObject(id obj)
{
    Class NewCls = MulleObjCLookupClassByNameUTF8String("NewClass");
    if (NewCls)
        MulleObjCInstanceSetClass(obj, NewCls);
}

```

## Summary

- **Include [`mulle-objc.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc.h)** to gain immediate access to all runtime functions without additional linking steps.
- **Use static inline wrappers** like `MulleObjCObjectPerformSelector*` and `MulleObjCObjectGetBOOL` for zero-overhead message sending and primitive access.
- **Lookup classes dynamically** with `MulleObjCLookupClassByNameUTF8String` and selectors with `MulleObjCCreateSelectorUTF8String` when compile-time types are unavailable.
- **Introspect capabilities** via `MulleObjCClassImplementsSelector` before dispatching to avoid runtime exceptions.
- **Modify instance classes** directly using `MulleObjCInstanceSetClass` for low-level object metamorphosis.

## Frequently Asked Questions

### What is the difference between `MulleObjCObjectPerformSelector0` and `mulle_objc_object_call`?

`MulleObjCObjectPerformSelector0` is a static inline wrapper defined in [`src/function/MulleObjCFunctions.h`](https://github.com/mulle-objc/mulleobjc/blob/main/src/function/MulleObjCFunctions.h) that provides a type-safe, ergonomic interface for sending messages with no arguments. It internally calls `mulle_objc_object_call` from [`mulle-objc-runtime/mulle-objc-runtime.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc-runtime/mulle-objc-runtime.h), which performs the actual method table lookup and dispatch. The wrapper adds no runtime overhead because the compiler inlines it, but it offers cleaner syntax and automatic handling of the meta-ABI.

### Do I need to link against a separate runtime library to use these functions?

No. All convenience wrappers in [`mulle-objc.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc.h) are `static inline` functions defined in headers. They compile directly into your object code, requiring no additional linking beyond the standard mulle-objc runtime. The underlying runtime functions they call are already linked through the standard MulleObjC environment.

### How does `MulleObjCClassImplementsSelector` differ from `respondsToSelector:`?

`MulleObjCClassImplementsSelector` checks only the specific class's method table, excluding inherited implementations, whereas `respondsToSelector:` traverses the entire inheritance hierarchy. Use the former when you need to know if a class defines a method itself, such as when checking for required protocol implementations or avoiding inherited behavior.

### Can I use these runtime functions in regular C code, or only in Objective-C .m files?

You can use these functions in any C or Objective-C source file. The mulle-objc runtime API is pure C, and the wrappers in [`mulle-objc.h`](https://github.com/mulle-objc/mulleobjc/blob/main/mulle-objc.h) are compatible with both `.c` and `.m` extensions. This allows you to write runtime introspection logic in C modules while maintaining interoperability with MulleObjC objects.