hy icon indicating copy to clipboard operation
hy copied to clipboard

Scope of functions resulting from a macro expansion

Open brandonwillard opened this issue 5 years ago • 3 comments

Would we ever want functions resulting from the expansion of an imported macro to share the macro's namespace and/or requires? Of course a macro can be made to import/require its expansion's dependencies, but let's say one wanted to explicitly limit such dependencies to the resulting function's namespace/closure and not the namespace in which the macro is evaluated.

This is related to the "auto-requires"-like functionality recently introduced in #1682, but it's not the same.

To illustrate, consider the following:

;; File test_b.hy
(defn test-fn []
  (print "hi"))
;; File test_a.hy
(import [test-b [test-fn]])

(defmacro fn-create []
  `(fn [] (test-fn)))
hy 0.15.0+39.gd2319dc using CPython(default) 3.6.6 on Linux
=> (require [test-a [fn-create]])
True
=> ((fn-create))
Traceback (most recent call last):
  File "/home/bwillard/projects/code/python/hy-master/hy/importer.py", line 173, in hy_eval
    return eval(ast_compile(expr, "<eval>", "eval"), globals, locals)
  File "<eval>", line 1, in <module>
  File "<eval>", line 1, in <lambda>
NameError: name 'test_fn' is not defined

In this example, or a similar one, would we ever want/expect ((fn-create)) to print "hi"?

brandonwillard avatar Nov 19 '18 04:11 brandonwillard

I think the root of this problem might be more closely aligned with the idea of macros returning function objects. If a macro could return a function object, then the macro designer could simply create a function in whatever namespace they wanted.

Currently, function objects can't be wrapped by a Hy object. Any ideas on how a function object could be represented in the Hy language model?

brandonwillard avatar Nov 19 '18 17:11 brandonwillard

I don't think we can do that, because Python AST can't.

Kodiologist avatar Nov 19 '18 18:11 Kodiologist

Maybe related to #919. You could sort of emulate having arbitrary Python objects in the AST using pickle. See also https://stackoverflow.com/questions/51675355/how-to-eval-a-cond-case-and-return-function-object

The easiest way for a macro to resolve to a function object defined in another namespace is probably to expand to something like __import__('foo').bar where bar is the function object you want that is defined in module foo.

gilch avatar Nov 20 '18 03:11 gilch

I'm reasonably confident that the way macro scoping works now is what we're going with for 1.0. It's what I've documented in detail in #2531.

Kodiologist avatar Nov 12 '23 18:11 Kodiologist