Libjulia: is it really necessary to wrap immutable variables to protect them and why?

Hello here,

I have a C wrapper that calls Julia functions using libjulia and wraps the result in an IdDict, for example:

int64_t jl_setindex_wrap_eval_string(int64_t index, const char* code)
{
    if (index == 0){
        jl_printf(jl_stderr_stream(), "ERROR: index is 0 (jl_setindex_wrap_eval_string)\n");
        return(0);
    }else if (code == NULL){
        jl_printf(jl_stderr_stream(), "ERROR: empty code string (jl_setindex_wrap_eval_string)\n");
        return(0);  
    }
    jl_value_t *res = jl_eval_string(code);
    JL_CHECK_EXCEPT(0)
    JL_GC_PUSH1(&res);
    jl_call3(setind, refs, res, jl_box_int64(index));
    JL_GC_POP();
    return(index);
}

Where setind is the setindex! function.

From the documentation (Embedding Julia: Embedding Julia · The Julia Language), I knew that, immutable variables “needs to be wrapped in an equivalent mutable container or, preferably, in a RefValue{Any} before it is pushed to IdDict .”. Here refs is an IdDict.

I use this code for mutable and immutable ((scalars and (named)Tuple) values since a while so I wanted to know why it is necessary and if this is mandatory.

Some informations about this? And which bad effects can happen? I have not encountered some.

Greg

As those docs say, what can go bad is that “the GC can free objects out from under you, rendering pointers invalid”.

AFAIU a jl_value_t in C is a boxed value (a Core.Box) that contains both the value and the type. It is heap-allocated and can be freed if the GC doesn’t think anyone has a pointer to it.

In particular, if the value is immutable and you pass it (the boxed value) to Julia, then Julia can unbox the value if the code using it is sufficiently type stable that the compiler knows the type. At this point the box is not needed and might be freed. Hence you need to “root” the value in a container that itself won’t be freed, e.g. a global in some module.

You might not have observed any ill effects just by luck, if the GC happened to not kick in, or perhaps if the boxed value happened to be rooted somewhere else.

2 Likes