Author Archives: Tamás K. Papp

My farewell to <code>@unpack</code>

By: Tamás K. Papp

Re-posted from: https://tamaspapp.eu/pages/blog/2025/farewell-to-unpack/index.html

First, a bit of Julia history. When Parameters.jl introduced the @unpack macro in 2015, it scratched an imporant itch for Julia users at the time, especially those coming from (Common) Lisp who were used to cl:with-slots and similar macros. Given any object with properties, say foo and bar, one could bring them into scope with

@unpack foo, bar = x

instead of a clumsy

foo = x.foo
bar = x.bar

The functionality was so useful that it was later (around 2019) factored out into its own tiny package, UnPack.jl.

Of course the Julia developers recognized how great this feature was, and Julia 1.7 (in 2021) brought us the property destructuring syntax

(; foo, bar) = x

But since 1.7 was not an LTS, many packages did not require that version and kept relying on @unpack. In 2023, SimpleUnPack.jl was written as a drop-in replacement for the most common use case while being easier on the compiler.

Since Julia 1.10 is an LTS, I am gradually removing @unpack from my packages whenever I happen to refactor them. This is, strictly speaking, not necessary (it would just work forever), but I like to simplify code when I happen to refactor it for some other reason. I am taking this opportunity to reflect on how useful it was.

There are quite a few lessons there about software development in general, and specifically for Julia:

  1. Macros are amazingly powerful. No wonder that Lisp users consider them a killer feature, they can extend the language with very useful syntax at essentially zero runtime and negligible compile time cost. It was a great decision for Julia to include them.

  2. The best way to extend a language with new features is to first implement them as a package. This allows experimentation and quick turnaround, leading to a polished end product that the language can include.

  3. Once your Julia code works, it will keep working for a long time, potentially forever in 1.x land. UnPack.jl still has 200 dependents. This allows developers to make upgrades at their own pace, prioritizing more urgent issues.

Bonus feature

This little Emacs snippet does the conversion from @unpack ... to (; ...), also working on multiline code etc, either on standalone files or whole packages opened in dired.

(defun my-julia-remove-unpack ()
  "Go from `@unpack' to `(; ...)` destructuring syntax. Works in dired mode and buffer."
  (interactive)
  (let* ((from (rx "@unpack"
                   (one-or-more space)
                   (or (seq "(" (group-n 1 (one-or-more (not "@"))) ")")
                       (group-n 1 (one-or-more (not (or ?@ ?\n))))
                       )
                   (one-or-more space)
                   "="))
         (to "(; \\1) ="))
    (cond
     ((eq major-mode 'julia-mode) (query-replace-regexp from to))
     ((eq major-mode 'dired-mode) (dired-do-query-replace-regexp from to))
     (t (message "Don't know what to do with mode %s" major-mode)))))

P.S.

(I am reviving my blog after a long break.)

TransformVariables.jl gets pretty printing

By: Tamás K. Papp

Re-posted from: https://tamaspapp.eu/pages/blog/2023/02-22-transformvariables-pretty-printing/index.html

A recent update (version 0.8.2) to TransformVariables.jl adds pretty printing of (nested) transformations. Eg what used to be

julia> using StaticArrays, TransformVariablesjulia> t = as((a = asℝ₊, b = as(Array, asℝ₋, 3, 3),
               c = corr_cholesky_factor(13),
               d = as((asℝ, corr_cholesky_factor(SMatrix{3,3}),
                       UnitSimplex(3), UnitVector(4)))))
TransformVariables.TransformTuple{NamedTuple{(:a, :b, :c, :d), Tuple{TransformVariables.ShiftedExp{true, Int64}, TransformVariables.ArrayTransformation{TransformVariables.ShiftedExp{false, Int64}, 2}, CorrCholeskyFactor, TransformVariables.TransformTuple{Tuple{TransformVariables.Identity, TransformVariables.StaticCorrCholeskyFactor{3, 3}, UnitSimplex, UnitVector}}}}}((a = asℝ₊, b = TransformVariables.ArrayTransformation{TransformVariables.ShiftedExp{false, Int64}, 2}(asℝ₋, (3, 3)), c = CorrCholeskyFactor(13), d = TransformVariables.TransformTuple{Tuple{TransformVariables.Identity, TransformVariables.StaticCorrCholeskyFactor{3, 3}, UnitSimplex, UnitVector}}((asℝ, TransformVariables.StaticCorrCholeskyFactor{3, 3}(), UnitSimplex(3), UnitVector(4)), 9)), 97)

which is a single line of 700+ characters (which your browser mercifully hides behind a scrollbar), we now have

julia> using StaticArrays, TransformVariables
[ Info: Precompiling TransformVariables [84d833dd-6860-57f9-a1a7-6da5db126cff]julia> t = as((a = asℝ₊, b = as(Array, asℝ₋, 3, 3),
                      c = corr_cholesky_factor(13),
                      d = as((asℝ, corr_cholesky_factor(SMatrix{3,3}),
                              UnitSimplex(3), UnitVector(4)))))
[1:97] NamedTuple of transformations
  [1:1] :a → asℝ₊
  [2:10] :b → 3×3×asℝ₋ (dimension 1)
  [11:88] :c → 13×13 correlation cholesky factor
  [89:97] :d → Tuple of transformations
    [98:98] 1 → asℝ
    [108:110] 2 → SMatrix{3,3} correlation cholesky factor
    [120:121] 3 → 3 element unit simplex transformation
    [131:133] 4 → 4 element unit vector transformation

which tells you which indices map to which part of the result.

Tables output with Literate.jl

By: Tamás K. Papp

Re-posted from: https://tamaspapp.eu/pages/blog/2022/markdown-tables/index.html

I recently wrote a very lightweight package called MarkdownTables.jl that makes it easy to embed tables using Literate.jl. It handles anything that works with Tables.jl:

using MarkdownTables
my_table = [(animal = "cat", legs = 4),
            (animal = "catfish", legs = 0),
            (animal = "canary", legs = 2)]
my_table |> markdown_table()
animal legs
cat 4
catfish 0
canary 2

Under the hood, it just wraps some basic Markdown with DisplayAs.jl:

my_table |> markdown_table(String) |> print
| animal  | legs |
|---------|------|
|     cat |    4 |
| catfish |    0 |
|  canary |    2 |

The default output is pretty basic — while the function has some options for formatting, it is recommended that you use CSS instead.

I expect that this pretty much rounds out the tooling I need for blogging with Franklin.jl. Feedback and PRs are of course welcome, but I intend to keep this package very basic.