In Chapter 12, we passed a simple callback. But real-world C libraries often take a callback and an opaque pointer (usually something like void * user_data) which allows you to store context data. However, if the library's author decided not to provide that, Affix allows you to bake the context into the callback itself using closures.

The Recipe

We will wrap a hypothetical iteration function that takes a callback but no data argument.

use v5.40;
use feature 'class';
no warnings 'experimental::class';
use Affix qw[:all];
use Affix::Build;

# 1. C Library
my $c = Affix::Build->new();
$c->add( \<<~'END', lang => 'c' );
    void iterate_3( void (*cb)(int) ) {
        cb(1); cb(2); cb(3);
    }
END
my $lib = $c->link;
affix $lib, 'iterate_3', [ Callback [ [Int] => Void ] ] => Void;

# 2. The Problem
# We want to sum these numbers into a Perl object.
# But the C function doesn't give us a slot to hand it the object directly.
class Sum {
    field $total = 0;
    method add($n) { $total += $n; }
    method get()   { $total; }
}
my $obj = Sum->new;

# 3. The Closure Solution
# We define the callback inside the scope where $obj exists.
# Perl closes over $obj.
my $cb = sub ($n) { $obj->add($n); };

# 4. Execute
iterate_3($cb);
say 'Total: ' . $obj->get();    # 6

How It Works