2

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.

ShadowRylander
  • 361
  • 2
  • 8

1 Answers1

2

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.

Kodiologist
  • 2,984
  • 18
  • 33
  • Got it; however, what do I do about requiring macros and their dependencies manually? For example, my `let-cwd` macro depends on `with-cwd`, so I have to require both, despite only using the former. – ShadowRylander Jul 20 '22 at 17:23
  • 1
    @ShadowRylander You can always include a `require` in the code your macro generates, but usually it's neater to write subroutines of macros as functions than as macros. – Kodiologist Jul 20 '22 at 23:22
  • Could you give me an example of that? I'm having a bit of trouble following! – ShadowRylander Jul 21 '22 at 01:26
  • 1
    @ShadowRylander That isn't something that's easily crammed into the comments of an unrelated question. – Kodiologist Jul 22 '22 at 11:18
  • Got it; asked another question [here](https://stackoverflow.com/questions/73084195/require-macros-from-the-same-file-in-another-macro). Thanks again for the help! – ShadowRylander Jul 22 '22 at 17:44