1

Let's say I have the following two files:

;; demo.scm
(define-module (demo)
  #:export (f))

(define (g x) 1)
(define (f x) (g x))

... and in the same directory:

;; use-demo.scm
(add-to-load-path ".")
(use-modules (demo))

(define (g x) (+ x 1))
(display (f 5))
(newline)

Running use-demo.scm in Guile (2), I get the output 1. So it looks like the function f has 'closed over' the function g that's defined in module demo. Is there any way to get around this? I really want to use the version of g that I've redefined in use-demo.scm.

Yawar
  • 11,272
  • 4
  • 48
  • 80

2 Answers2

4

OK, just for the record, I did some research and am posting the solution to this specific problem in case it helps someone.

The trick is to not redefine g locally, but rather to 'inject' the new function into the demo module's mapping of names to values.

(add-to-load-path ".")
(use-modules (demo))

(module-define! (resolve-module '(demo)) 'g
  (lambda (x) (+ x 1)))

(display (f 5))
(newline)
Yawar
  • 11,272
  • 4
  • 48
  • 80
0

If you have specific functions that you'd like to be able to override, you could make them configurable using parameters. This has some advantages:

  1. You don't need to call reload-module to put the module back in its original configuration.
  2. The changes only apply for the scope of the code which needs the modified behaviour.
  3. It works properly when using multiple threads.

Obviously, the main disadvantage is that you need to add some boilerplate for each function that you want to allow to be overridden (although that's what hygienic macros are for, hehe).

The following code may work. I haven't run it.

;; demo.scm

(define-module (demo)
  #:export (f))

(define (default-g x) 1)
(define p (make-parameter default-g))
(define (f x) ((p) x))


;; use-demo.scm
(add-to-load-path ".")
(use-modules (demo))

(define (my-g x) (+ x 1))
(parameterize ((@@ (demo) p) my-g)
  (display (f 5))
  (newline))

Obviously, if you can provide some additional information about what the application for this capability is, I might be able to suggest alternative approaches (there are a few others).

Peter T.B. Brett
  • 1,250
  • 11
  • 20
  • Thanks Peter. I ended up doing this: https://github.com/yawaramin/ggspec/blob/7feaef3b00348cac8415ec1f47d3057496b81009/lib.scm#L81 – Yawar Feb 27 '14 at 02:39
  • 1
    Hmm. Your lightweight unit-testing framework is less minimal than mine (https://github.com/peter-b/geda-gaf/blob/master/libgeda/scheme/unit-test.scm). :-P You may wish to steal my idea of an `assert-thrown` macro. – Peter T.B. Brett Feb 28 '14 at 05:08
  • Obviously in a "real program" your `stub` macro could be racy if more than one thread is running, but it looks like an excellent solution for testing purposes! – Peter T.B. Brett Feb 28 '14 at 05:11
  • Thanks, I believe I have similar logic in my `error?` macro. I'll probably extend it to test for a _specific type_ of error. And--agreed, once you throw multiple threads into the mix, you can't be sure of anything. – Yawar Feb 28 '14 at 17:02