-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Description
I need a way to hook into the capture of variables in closures, based on their type, as part of my work on BorrowChecker.jl. Currently this is not possible in Julia with any internal mechanism that I am aware of.
In particular, I’d like to prevent a custom struct (in my case, any variable wrapped with a specific struct) from being captured by any closure. This API might look like the following:
struct A; end
struct B; end
# block capturing
Core.hook_capture(::A) = error("You cannot capture variables of type `A` in closures")
# no-op (the default behavior)
Core.hook_capture(b::B) = b
But I don't know much about the process of lowering so I could suggesting something in the totally wrong direction here.
Ideally I would like a full hook API like this so that I can track information about such capturing. For example, in BorrowChecker.jl, the user would be able to capture certain types (Borrowed
) but not others (Owned
, OwnedMut
, and BorrowedMut
). And when those Borrowed
objects are captured, I would like to log it as a new reference. In other words, I would like the result of this Core.hook_capture
to be what is actually passed to the closure function.
But if there's just a Core.allow_capture(::Type{A}) = false
API, that is also good with me.
A hacky workaround using Cassette.jl can intercept `Core.setfield!` in some cases (e.g., when boxing occurs), but:
function Cassette.overdub(ctx::ManagedCtx, f, args...)
if f == Core.setfield! &&
length(args) == 3 &&
args[1] isa Core.Box &&
args[2] == :contents &&
args[3] isa Union{Owned,OwnedMut,BorrowedMut} #= the type to track =#
symbol = args[3].symbol
error("You are not allowed to capture bound variable `$(symbol)` inside a closure.")
end
#= Other overdubbing =#
end
- This doesn’t cover all capture paths.
- This is fragile.
- This requires the user to execute a macro over their executed code to set up the contextual dispatch.
- Cassette.jl is no longer maintained and is broken on recent Julia versions.
A hook in Julia is required to enable this safety feature for constrained programming models such as BorrowChecker.jl, where I would like to prevent capture of specific types.