hy

Non-existent hy macros runs assertions, but fails appropriately with everything else


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.


Solution

  • 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 if f is a function whereas h is a macro that produces Python-level statements. So if you need to be sure that g is called first, call it before f.

    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.