bug#43025: re-export-public-interface fails on Guile 3

Leo Prikler <[email protected]>
Newsgroups gmane.lisp.guile.bugs
Message-ID <[email protected]>
Hi Dale.

Am Montag, den 24.08.2020, 12:11 -0400 schrieb Dale Smith:
> This is actually reported by daviid on IRC.
> 
> This definition of re-export-public-interface works fine on Guile
> 2.x,
> fails with Guile 3:
> (hope this makes it through the mails cleanly)

> ;;;
> ;;; re-export-public-interface
> ;;;
> 
> [...]
I'm going to skip the specifics of the macro here, it is not needed for
an MWE.

> ;;;
> ;;; A module that uses the above
> ;;;
> 
> 
> (define-module (a)
>   #:use-module (srfi srfi-1)
>   #:use-module (modules)
> 
>   #:export (map-a))
> 
> 
> (eval-when (expand load eval)
>   (re-export-public-interface (srfi srfi-1)))
> 
> 
> (define (map-a)
>   (map (lambda (item)
>          (display item)
>          (display " "))
>     (iota 5))
>   (newline)
>   (values))
> 

For the sake of minimalism, I will shorten this to

(define-module (a))

(module-use! (module-public-interface (current-module))
             (resolve-interface '(srfi srfi-1)))

I hope you don't mind.

> [sessions]

My solution for this problem would be to build on some of the module
"intrinsics", which sadly are not all that well documented.

(define-module (a))

(let ((obs (module-obarray (resolve-interface '(srfi srfi-1))))
      (iface (module-public-interface (current-module))))
  (hash-fold
   (lambda (key value seed)
     (module-add! iface key value)
     seed)
   *unspecified*
   obs))

If you want to make this a macro, you really only need to syntax-
unquote a module into the (resolve-interface ...) portion of this
snippet.

Some sessions for reference:

GNU Guile 3.0.4
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (add-to-load-path "/tmp")
scheme@(guile-user)> ,use (a)
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /tmp/a.scm
;;; compiled $HOME/.cache/guile/ccache/3.0-LE-8-4.3/tmp/a.scm.go
scheme@(guile-user)> map
WARNING: (guile-user): imported module (a) overrides core binding `map'
$1 = #<procedure map (f l) | (f l1 l2) | (f l1 . rest)>
scheme@(guile-user)> ,q

GNU Guile 3.0.2
Copyright (C) 1995-2020 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (add-to-load-path "/tmp")
scheme@(guile-user)> ,use (a)
;;; note: source file /tmp/a.scm
;;;       newer than compiled /home/yuri/.cache/guile/ccache/3.0-LE-8-
4.2/tmp/a.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /tmp/a.scm
;;; compiled $HOME/.cache/guile/ccache/3.0-LE-8-4.2/tmp/a.scm.go
scheme@(guile-user)> map
WARNING: (guile-user): imported module (a) overrides core binding `map'
$1 = #<procedure map (f l) | (f l1 l2) | (f l1 . rest)>
scheme@(guile-user)> ,q

GNU Guile 2.2.7
Copyright (C) 1995-2019 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (add-to-load-path "/tmp")
scheme@(guile-user)> ,use (a)
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;;       or pass the --no-auto-compile argument to disable.
;;; compiling /tmp/a.scm
;;; compiled $HOME/.cache/guile/ccache/2.2-LE-8-3.A/tmp/a.scm.go
scheme@(guile-user)> map
$1 = #<procedure map (f l) | (f l1 l2) | (f l1 . rest)>
scheme@(guile-user)> ,q

Interestingly, versions newer than 3.0.2 warn about core override in
this case, as does #:re-export.  If I am not mistaken, this is the way
re-export works for variables normally.  module-use! on the other hand
does not modify the module-obarray, it instead adds the module to a
list of uses, which are handled separately in variable lookup during
`module_imported_variable`.  This C function does look up variables
exported by a module, but does not traverse module-uses recursively.  I
have no idea, how this works for 2.2.7, I only checked the Guile 3 code
here.

Regards,
Leo
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.