Callbacks

    Then you can pass a function (a Proc) like this:

    1. X.callback(f)

    If you define the function inline in the same call you can omit the parameter types, the compiler will add the types for you based on the fun signature:

    1. X.callback ->(x) { x + 1 }

    Note, however, that functions passed to C can’t form closures. If the compiler detects at compile-time that a closure is being passed, an error will be issued:

    If the compiler can’t detect this at compile-time, an exception will be raised at runtime.

    If you want to pass NULL instead of a callback, just pass nil:

    1. # Same as callback(NULL) in C
    2. X.callback nil

    Most of the time a C function that allows setting a callback also provides a parameter for custom data. This custom data is then sent as an argument to the callback. For example, suppose a C function that invokes a callback at every tick, passing that tick:

    1. fun on_tick(callback : (Int32, Void* ->), data : Void*)

    To properly define a wrapper for this function we must send the Proc as the callback data, and then convert that callback data to the Proc and finally invoke it.

    Note that we save the boxed callback in @@box. The reason is that if we don’t do it, and our code doesn’t reference it anymore, the GC will collect it. The C library will of course store the callback, but Crystal’s GC has no way of knowing that.

    Raises annotation

    The compiler infers this annotation for a method if it invokes a method that is marked as @[Raises] or raises (recursively).

    However, some C functions accept callbacks to be executed by other C functions. For example, suppose a fictitious library:

    1. lib LibFoo
    2. fun store_callback(callback : ->)
    3. fun execute_callback
    4. end

    If the callback passed to store_callback raises, then execute_callback will raise. However, the compiler doesn’t know that execute_callback can potentially raise because it is not marked as @[Raises] and the compiler has no way to figure this out. In these cases you have to manually mark such functions:

    1. lib LibFoo
    2. fun store_callback(callback : ->)
    3. @[Raises]
    4. fun execute_callback

    If you don’t mark them, begin/rescue blocks that surround this function’s calls won’t work as expected.