Skip to content

Commit

Permalink
Merge pull request #185 from sogaiu/tweak-fiber-docs
Browse files Browse the repository at this point in the history
Tweak fiber docs
  • Loading branch information
bakpakin committed Jun 8, 2023
2 parents cee9795 + 4483903 commit 39fa2ee
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 28 deletions.
31 changes: 16 additions & 15 deletions content/docs/fibers/dynamic_bindings.mdz
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
There are situations where the programmer would like to thread a parameter
through multiple function calls, without passing that argument to every function
explicitly. This can make code more concise, easier to read, and easier to
extend. Dynamic bindings are a mechanism that provide this in a safe and easy to
extend. Dynamic bindings are a mechanism that provides this in a safe and easy to
use way. This is in contrast to lexically-scoped bindings, which are usually
superior to dynamically-scoped bindings in terms of clarity, composability, and
performance. However, dynamic scoping can be used to great effect for implicit
Expand Down Expand Up @@ -54,38 +54,39 @@ print function @code`pp`.
(def curr-env (fiber/getenv (fiber/current)))

# The dynamic bindings we want to use
(def my-env {:pretty-format "Inside myblock: %.20P"})
(def my-env @{:pretty-format "Inside myblock: %.20P"})

# Set up a new fiber
(def f (fiber/new myblock))
(fiber/setenv f (table/setproto my-env curr-env))

# Run the code
(pp [1 2 3]) # prints "[1 2 3]"
(resume f) # prints "Inside myblock: [1 2 3]"
(pp [1 2 3]) # prints "[1 2 3]"
(pp [1 2 3]) # prints "(1 2 3)"
(resume f) # prints "Inside myblock: (1 2 3)"
(pp [1 2 3]) # prints "(1 2 3)"
```

This is verbose so the core library provides a macro, @code`with-dyns`, that
makes it much clearer in the common case.

@codeblock[janet]```
(pp [1 2 3]) # prints "[1 2 3]"
# prints "Inside with-dyns: [1 2 3]"
(pp [1 2 3]) # prints "(1 2 3)"
# prints "Inside with-dyns: (1 2 3)"
(with-dyns [:pretty-format "Inside with-dyns: %.20P"]
(pp [1 2 3]))
(pp [1 2 3]) # prints "[1 2 3]"
(pp [1 2 3]) # prints "(1 2 3)"
```

## When to use dynamic bindings

Dynamic bindings should be used when you want to pass around an implicit, global
context, especially when you want to automatically reset the context if an error
is raised. Since a dynamic binding is tied to the current fiber, when a fiber
exits the context is automatically unset. This is much easier and often more
efficient than manually trying to detect errors and unset context. Consider the
following example code, written once with a global var and once with a dynamic
binding.
Dynamic bindings should be used when you want to pass around an
implicit, global context, especially when you want to automatically
reset the context if an error is raised. Since a dynamic binding is
tied to the current fiber, when a fiber exits the context is
automatically unset. This is much easier and often more efficient than
manually trying to detect errors and unset the context. Consider the
following example code, written once with a global var and once with a
dynamic binding.

### Using a global var

Expand Down
10 changes: 5 additions & 5 deletions content/docs/fibers/error_handling.mdz
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ its second clause.

@codeblock[janet]```
(try
(do
(print "inside block...")
(error "oops")
(print "will never get here"))
([err] (print "caught error: " err)))
(do
(print "inside block...")
(error "oops")
(print "will never get here"))
([err] (print "caught error: " err)))
```

### @code`protect`
Expand Down
17 changes: 9 additions & 8 deletions content/docs/fibers/index.mdz
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ fiber yields or throws an error, control is returned to the calling fiber. The
parent fiber must then check what kind of state the fiber is in to differentiate
errors from return values from user-defined signals.

To create a fiber, user the @code[fiber/new] function. The fiber constructor
take one or two arguments. The first, necessary argument is the function that
the fiber will execute. This function must accept an arity of zero. The next
optional argument is a collection of flags checking what kinds of signals to
trap and return via @code[resume]. This is useful so the programmer does not
need to handle all different kinds of signals from a fiber. Any un-trapped
signals are simply propagated to the previous calling fiber.
To create a fiber, use the @code[fiber/new] function. The fiber
constructor takes one or two arguments. The first argument (required)
is the function that the fiber will execute. This function must accept
an arity of zero. The next argument (optional) is a collection of
flags checking what kinds of signals to trap and return via
@code[resume]. This is useful so the programmer does not need to
handle all of the different kinds of signals from a fiber. Any
untrapped signals are simply propagated to the previous calling fiber.

@codeblock[janet](```
(def f (fiber/new (fn []
Expand All @@ -55,7 +56,7 @@ signals are simply propagated to the previous calling fiber.
## Using fibers to capture errors

Besides being used as coroutines, fibers can be used to implement error handling
(ie: exceptions).
(i.e. exceptions).

@codeblock[janet](```
(defn my-function-that-errors []
Expand Down

0 comments on commit 39fa2ee

Please sign in to comment.