In the following code:
(eval-and-compile (import os hy))
(eval-and-compile (import pathlib [Path]))
; (defmacro with-cwd [dir #* body]
; (setv cwd (hy.gensym))
; `(let [ ~cwd (.cwd Path) ]
; (try (.chdir os ~dir)
; ~@body
; (finally (.chdir os ~cwd)))))
(setv cookies (/ (.cwd Path) "cookies"))
; This fails with an `AssertionError'
(with-cwd cookies (assert (= (.cwd Path) cookies)))
; This fails with a `NameError'
(with-cwd cookies (.cwd Path))
Similarly, any functions or macros depending on the missing macro errors out in the same way, and if, for example, I'm importing or requiring a function or macro that depends on the missing macro, the same thing happens; basically, I have to import or require a function or macro as well as its dependencies manually.
Is this a bug, or am I missing something about the order of Python / Hy assertions? I expected the first case to fail with a NameError
as well.
This is a documented quirk:
Like many programming languages, but unlike Python, Hy doesn't guarantee in all cases the order in which function arguments are evaluated. More generally, the evaluation order of the child models of a
hy.models.Sequence
is unspecified. For example,(f (g) (h))
might evaluate (part of)(h)
before(g)
, particularly iff
is a function whereash
is a macro that produces Python-level statements. So if you need to be sure thatg
is called first, call it beforef
.
In this case, the assert
statement has gotten pulled out of the function call ((with-cmd …)
being a function call, since there is no macro named with-cmd
) and evaluated before the symbol with-cmd
itself.