Stream: helpdesk (published)

Topic: JET: access to binding in a world prior to its definition


view this post on Zulip James Wrigley (Jun 27 2025 at 11:15):

I'm seeing this warning (among a bazillion others) when running JET.jl on 1.12 on an IJulia branch:

julia> report_package("IJulia"; toplevel_logger=nothing)
WARNING: Detected access to binding `IJulia.heartbeat_thread` in a world prior to its definition world.
  Julia 1.12 has introduced more strict world age semantics for global bindings.
  !!! This code may malfunction under Revise.
  !!! This code will error in future versions of Julia.
Hint: Add an appropriate `invokelatest` around the access to this binding.
To make this warning an error, and hence obtain a stack trace, use `julia --depwarn=error`.

This is the function in question: https://github.com/JuliaLang/IJulia.jl/blob/42c99f1aeb06b7bd514b1888e84a1060440910aa/src/heartbeat.jl#L8

But I can't figure out where the warning is coming from because heartbeat_thread() is only ever called in start_heartbeat(), which is defined afterwards. Does anyone know why it's triggering that warning?

view this post on Zulip Andy Dienes (Jun 27 2025 at 13:22):

friendly neighborhood LLM suggests it's due to the use of @cfunction(heartbeat_thread, Cint, (Ptr{Cvoid},)) which is trying to use heartbeat_thread at macro expansion time prior to the compilation of heartbeat_thread function

view this post on Zulip James Wrigley (Jun 27 2025 at 13:25):

That... would make sense :thinking: But then I'm not sure how to fix it without making a runtime cfunction or moving the cfunction to the top-level.

view this post on Zulip Andy Dienes (Jun 27 2025 at 13:48):

what if you take heartbeat_thread to a separate file and then include it in to the file where you define start_heartbeat ?

view this post on Zulip Andy Dienes (Jun 27 2025 at 13:49):

LLM also suggests moving cfunction to top level

const _heartbeat_c =
    @cfunction(heartbeat_thread, Cint, (Ptr{Cvoid},))  # executed once at load time

# 3️⃣  use the cached pointer
function start_heartbeat(kernel)
    hb = kernel.heartbeat[]
    hb.linger = 0
    ccall(:uv_thread_create, Cint,
          (Ptr{Int}, Ptr{Cvoid}, Ptr{Cvoid}),
          kernel.heartbeat_threadid, _heartbeat_c, hb)
end

but I do see how that's a bit uglier


Last updated: Jul 01 2025 at 04:54 UTC