racket / rackunit

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`require/expose` does not work on macros

lihebi opened this issue · comments

require/expose can require an unprovided binding from a module. But it only works on functions, not macros. E.g.

(module aaa racket
  (define (foo a b) (+ a b))
  (define-syntax-rule (myadd x y)
    (+ x y)))
(require rackunit)
;; OK
(require/expose 'aaa (foo))
;; ERROR: myadd: use does not match pattern: (myadd x y)
(require/expose 'aaa (myadd))

The relative code blocks implementing require/expose:

(define (dynamic-require/expose* mod names)
;; Make sure module the module is instantiated
(dynamic-require mod #f)
;; Get the module namespace
(parameterize ((current-namespace (module->namespace mod)))
(apply values (map eval names))))

The reason is quite simple: transformer bindings are not available at runtime thus (apply eval names) thows error. Is it possible to make require/expose work on macros?

I don't think it's possible, nor do I think it's something we want to encourage in the first place. What were you planning to use this functionality for?

Thanks for your reply.

I'm developing a module-aware IDE for racket. In particular, a user develops code in one module (A) and requires it in another (B), and keeps doing this without restarting the racket runtime. Without require/expose, one has to re-declare module A every time a new function/macro is added to A, which is not very efficient when module A becomes large.

I don't think you need require/expose for that. You can use dynamic-rerequire instead, possibly combined with all-defined-out. You might also be interested in racket-reloadable, which uses dynamic-rerequire to implement hot code reloading for webserver-like programs.

Thanks for the pointers! If I understand correctly, you mean:

;; define module A with all-defined-out
(module A racket
  (provide (all-defined-out))
  (define a 1))
;; dynamically add a new binding b
(enter! 'A)
(define b 2)
(enter! #f)

;; try to reload
(dynamic-rerequire ''A)

;; OK
(dynamic-require ''A 'a)

;; ERROR: dynamic-require: name is not provided, name: 'b
(dynamic-require ''A 'b)

;; OK
(require/expose 'A (b))

Looks like this is not working, all-defined-out cannot pick up a new dynamically added binding. b.