Defining a global variable in a nested quote

Suppose we have the following code:

foo() = begin
    var_name = gensym()
    is_init_var_name = gensym()

    quote
        const $is_init_var_name = Ref{Bool}(false)

        set_val(x) = begin
            if $is_init_var_name[]
                $var_name[] = x
            else
                $is_init_var_name[] = true
                quote
                    const $$var_name = Ref{$(x |> typeof)}($x)
                end |> eval
            end
        end

        get_val() = $var_name[]

        is_val_init() = $is_init_var_name[]
    end |> eval
end

After calling foo() we can check that is_val_init indeed returns false. Calling get_val() is an error: UndefVarError: ##312 not defined which is also expected.

What I am confused about is why when I call set_val(100) I get the error: UndefVarError: ##312 not defined again.

It seems that the double dollar sign is not interpolating as I am expecting. It seems to be trying to access the underlying value referred to the by the symbol that is var_name. When in reality I am just trying to get the symbol so I can assign to it the same way I did with is_init_var_name in the un-nested quote.

A single dollar sign also won’t work for obvious reasons. That is var_name is not a variable in the function set_val.

I need the result to be a global constant Ref for performance reasons. I can achieve a global variable by just not using a nested quote and using the keyword global. But then it wouldn’t be const which doesn’t work for me.

It seems the following hack works:

foo() = begin
    var_name = gensym()
    var_name_str = string(var_name)
    is_init_var_name = gensym()

    quote
        const $is_init_var_name = Ref{Bool}(false)

        set_val(x) = begin
            if $is_init_var_name[]
                $var_name[] = x
            else
                $is_init_var_name[] = true
                var_name_local = Symbol($var_name_str)
                quote
                    const $var_name_local = Ref{$(x |> typeof)}($x)
                end |> eval
            end
        end

        get_val() = $var_name[]

        is_val_init() = $is_init_var_name[]
    end |> eval
end

I don’t know if there is just something hacky solution built into Julia that interprets single dollar signs in front of an assignment differently than elsewhere (interpolates to the Symbol rather than the underlying value). And somehow that solution is not extending to double dollar signs and the like.

Does anyone know more about this?

1 Like