# \[ANN\] Package Conditions.jl

**URL:** <https://discourse.julialang.org/t/ann-package-conditions-jl/104863>\
**Category:** Package Announcements\
**Created:** [October 11, 2023, 4:09pm UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863 "2023-10-11T16:09:57Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [October 11, 2023, 4:09pm UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863/1 "2023-10-11T16:09:57Z")

</div>

[Conditions.jl](https://github.com/bertschi/Conditions.jl) is a proof-of-principle implementation of a Common Lisp like condition system.  
In contrast to _throwing an exception_, **signalling a condition** does not unwind the stack. This allows a condition handler to resume execution, e.g.,

```julia
using Conditions

function seq()
    n = 1
    while n < 10
        @signal n # Think: `yield n`
        n += 1
    end
end

handler_bind(Handler(Any, c -> @show c)) do
    seq()
end

```

See the package README for more examples and how **restarts** allow more elaborate error recovery than `try-catch`.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [October 11, 2023, 8:06pm UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863/2 "2023-10-11T20:06:25Z")

</div>

Looks great to me and adds a really nice feature from Common Lisp I have somewhat missed in Julia!

I also expected something like this to pop up soon since special bindings where just [merged recently](https://github.com/JuliaLang/julia/pull/50958). However you don’t seem to use them and instead rely on `task_local_storage`. This has the limitation that handlers can’t be set across tasks but it would just be a small change to switch to `ScopedValue`s as storage instead 😃

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [October 11, 2023, 9:03pm UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863/3 "2023-10-11T21:03:46Z")

</div>

Thanks, had not seen `ScopedValues` and thus took `task_local_storage` for special variables. Its certainly interesting if handlers could cross task boundaries … have not thought about the implications though.

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [October 11, 2023, 10:47pm UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863/4 "2023-10-11T22:47:19Z")

</div>

Ok, have switched to `ScopedValues` … this is pretty cool actually as you can now drive several tasks on different threads from a single handler:

```julia
using Conditions

function seq(n)
    i = 1
    while i < n
        @restart_case @signal(i) begin
            :next => () -> nothing
        end
        @show Threads.threadid()
        i += 1
    end
end

function donext(c)
    sleep(0.01)
    @show c
    invoke_restart(find_restart(:next))
end

```

```julia-repl
julia> @sync handler_bind(Handler(Any, donext)) do
           Threads.@spawn seq(3)
           Threads.@spawn seq(5)
       end
c = 1
Threads.threadid() = 2
c = 1
Threads.threadid() = 5
c = 2
Threads.threadid() = 2
c = 2
Threads.threadid() = 5
c = 3
Threads.threadid() = 5
c = 4
Threads.threadid() = 5
Task (done)

```

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [October 12, 2023, 4:34am UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863/5 "2023-10-12T04:34:05Z")

</div>

This looks kind of cool, but I can’t immediately grasp from your examples what you’d actually use this for. For example, Infiltrator is mentioned in the readme, but does it make a difference whether that is run from inside a function or from the outside, after the detour of a signal?

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [October 12, 2023, 9:17pm UTC](https://discourse.julialang.org/t/ann-package-conditions-jl/104863/6 "2023-10-12T21:17:58Z")

</div>

Not sure if I understand you correctly, but the basic difference between `throw` and `@signal` is that with the former, you can only end up lower on the stack inside some `try-catch` form, whereas the latter leaves the stack untouched and a handler from `handler_bind` runs on top of the current stack. This can be used in several ways:

1. When `toggle_interactive(true)` there is a default handler which runs `@infiltrate` on top of the stack, i.e., you get dumped into a debug prompt exactly at the place where `@signal` was called (and not where it got caught/handled). It does not matter how you got there or where it was handled – if that’s what you meant with “does it make a difference whether that is run from inside a function or from the outside”.

2. Using `@restart_case` you can mark positions on the stack which can be used to resume execution later on. In particular, a handler lower on the stack can decide to continue execution of the program on one of such restart points. [Practical Common Lisp](https://gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts) has a slightly larger example showing why and how this can be used for error recovery. For illustration, I have just ported this [example](https://github.com/bertschi/Conditions.jl/blob/main/examples/gigamonkeys.jl).

In any case, thanks for taking a look.
