In C, OOP is often simulated using structs containing function pointers. This pattern is commonly known as a vtable and allows a library to call different implementations of a function depending on the object it's holding. With Affix, you can populate these fields with Perl subroutines, effectively creating a Perl class that C can call into.

We're going to use a vtable to build a hypothetical plugin system. The C library expects a struct containing handlers for init and process.

The Recipe

use v5.40;
use Affix qw[:all];
use Affix::Build;

# 1. Compile C Library
my $c = Affix::Build->new();
$c->add( \<<~'END', lang => 'c' );
    typedef struct {
        const char* name;
        int (*init)(void);
        void (*process)(const char* data);
    } Plugin;

    void run_plugin(Plugin* p, const char* data) {
        if (p->init()) {
            p->process(data);
        }
    }
    END
my $lib = $c->link;

# 2. Define Types
# The struct fields must include the Callback signature.
typedef Plugin => Struct [ name => String, init => Callback [ [] => Int ], process => Callback [ [String] => Void ] ];

# 3. Bind
affix $lib, 'run_plugin', [ Pointer [ Plugin() ], String ] => Void;

# 4. Create the Perl "Object"
# We use a HashRef to represent the struct.
# The callback fields are populated with anonymous subs.
my $my_plugin = {
    name => 'PerlPlugin v1.0',
    init => sub {
        say 'Initializing Perl Plugin...';
        return 1;    # Success
    },
    process => sub ($data) {
        say 'Processing data in Perl: ' . $data;
    }
};

# 5. Call C
# We pass the reference to our hash. Affix packs it into the C struct,
# creating trampolines for the subroutines automatically.
run_plugin( $my_plugin, 'Some Input Data' );

How It Works

Kitchen Reminders