I might be missing something crucial, but I think we can already do this today with ScopedValues. For example, taking the error-handling example from the blog post @mnemnion linked, we can write this in Julia as
using ScopedValues
function getName(user)
name = user.name
if name === nothing
name = perform("ask_name")
end
return name
end
function makeFriends(user1, user2)
push!(user1.friendNames, getName(user2))
push!(user2.friendNames, getName(user1))
end
const arya = (; name=nothing, friendNames=[])
const gendry = (; name="Gendry", friendNames=[])
const HANDLER = ScopedValue{Union{Nothing, Function}}(nothing)
function perform(effect)
handler = HANDLER[]
isnothing(handler) && error("Could not perform effect $effect; no handler")
return handler(effect)
end
with(HANDLER => function(effect)
if effect === "ask_name"
return "Arya Stark"
end
error("No handler for effect $effect")
end) do
makeFriends(arya, gendry)
end
@show arya.friendNames gendry.friendNames;
which results in
arya.friendNames = Any["Gendry"]
gendry.friendNames = Any["Arya Stark"]
(ScopedValues are in Base in v1.11 due to this PR, and available in earlier versions via https://github.com/vchuravy/ScopedValues.jl.)
edit: I see Conditions.jl uses ScopedValues, so I guess their relevance here is old news