Phil Hagelberg: 1 Propagate error messages in -?> and -??> macros. 3 files changed, 11 insertions(+), 6 deletions(-)
This changes the nil-safe threading macros to be more useful in chains involving functions which use the nil,msg pattern to indicate an error. For instance, previously this would have only printed nil, but now it prints nil along with the error message.
Talking this thru a little more, I think the limitation of only returning two values here is a mistake. In particular there are certain libraries that return nil, msg, error-code when there is a problem. The existing implementation could just bump it to hard-coding three values, but that seems tacky. We can't support an arbitrary number of values without performance overhead, so I think it would be better to introduce a new form specifically for this case of error handling. I think we should take a look at Elixir for this; in particular their `with` special form is a particularly elegant way of expressing this problem using a series of patterns where the result of one is fed into the next. It's a bit like a mashup of `match` and `->`: https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1 I'll play around a little with a proposal for a similar form in Fennel. -Phil
(fn e [x] (values nil "oh no")) (fn f2  (error "this never runs")) (print (-?> "/tmp/hi" (io.open :w) (: :write "whaaaat up") (e) (f2))) ;; -> nil oh no There is some risk that this will cause incompatibilities in cases where code currently assumes that these macros will return only a single value. However, I believe their increased utility for error handling outweighs this downside. --- changelog.md | 1 + reference.md | 4 ++++ src/fennel/macros.fnl | 12 ++++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/changelog.md b/changelog.md index 542491a..9ae7e26 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ## 0.9.0 / ??? +* Return the second value when ending a `-?>` or `-?>>` chain early * Support `&as` inside pattern matches * Include stack trace for errors during macroexpansion * The `sym` function in compile scope now takes a source table second argument diff --git a/reference.md b/reference.md index 4615634..b7c46fb 100644 --- a/reference.md +++ b/reference.md @@ -909,6 +909,10 @@ the checks in `-?>` and `-?>>` prevent the same from happening there without performance overhead, so these pipelines are limited to a single value. +However, when a chain ends early due to one step returning false or nil, +the entire form will return two values, since usually this means that +the second value is an error message. + > Note that these have nothing to do with "threads" used for > concurrency; they are named after the thread which is used in > sewing. This is similar to the way that `|>` works in OCaml and Elixir. diff --git a/src/fennel/macros.fnl b/src/fennel/macros.fnl index 76fc7ce..dcfd231 100644 --- a/src/fennel/macros.fnl +++ b/src/fennel/macros.fnl @@ -38,12 +38,12 @@ Same as -> except will short-circuit with nil when it encounters a nil value." (let [els [...] e (table.remove els 1) el (if (list? e) e (list e)) - tmp (gensym)] + tmp (gensym) msg (gensym)] (table.insert el 2 tmp) - `(let [,tmp ,val] + `(let [(,tmp ,msg) ,val] (if ,tmp (-?> ,el ,(unpack els)) - ,tmp))))) + (values ,tmp ,msg)))))) (fn -?>>* [val ...] "Nil-safe thread-last macro. @@ -53,12 +53,12 @@ Same as ->> except will short-circuit with nil when it encounters a nil value." (let [els [...] e (table.remove els 1) el (if (list? e) e (list e)) - tmp (gensym)] + tmp (gensym) msg (gensym)] (table.insert el tmp) - `(let [,tmp ,val] + `(let [(,tmp ,msg) ,val] (if ,tmp (-?>> ,el ,(unpack els)) - ,tmp))))) + (values ,tmp ,msg)))))) (fn ?dot [tbl k ...] "Nil-safe table look up. -- 2.20.1
Phil Hagelberg <firstname.lastname@example.org> writes: