Hi Mark or anyone else able to help, Thanks again for raising this issue with my guile-file-names module:
Mark H Weaver writes: > I see that you are using 'set!' to mutate several core bindings in the > (guile) module to much slower GOOPS generic functions. For example, you > 'set!' the core 'append' procedure to a GOOPS generic function that adds > support for appending together your <file-name> objects. I've renamed the <file-name> append methods to something else that fits well with the names of other methods. However, I would still like to provide versions of all of the various file-system procedures specialized on <file-name> objects. Herein lies the rub: naturally, none of the examples that I see in the SRFIsn use GOOPS. I can't figure out how to export from my module methods that are derived from GOOPS generic functions of built-in procedures. Take, for example, providing absolute-file-name? for <file-name> objects without clobbering the ability to call it on strings. >From what I understand, this should simply entail calling define-method and adding the symbol to the define-module #:replace list. define-method will first call define-generic an absolute-file-name? and it will use the original procedure as the default of the generic function. So, as simple as: (define-module (file-names) ... #:replace (absolute-file-name?)) (define-method (absolute-file-name? (f <file-name>)) ...) When using the module, absolute-file-name? now works for <file-name> objects, however it no longer works for strings: scheme@(guile-user)> (absolute-file-name? "/home/brandon/.guile") ERROR: In procedure scm-error: No applicable method for #<<generic> absolute-file-name? (1)> in call (absolute-file-name? "/home/brandon/.guile") So, the original procedure isn't being used as the default for the generic function? How should I handle this? Obviously I can't just do (define-method (absolute-file-name? (f <file-name>)) ...) (define-method (absolute-file-name? (f <string>)) (absolute-file-name? f)) Because of infinite recursion. I can try something like this: (let ((old-absolute-file-name? absolute-file-name?)) (define-generic absolute-file-name?) (define-method (absolute-file-name? (f <file-name>)) (proper-list? (route f))) (define-method (absolute-file-name? (f <string>)) (old-absolute-file-name? f))) But that strangely gives me this upon compiling the module: While compiling expression: Unbound variable: absolute-file-name? I'm not sure what to make of that. A compile-time error, but why? That last attempt, of course, looks a lot like what's recommended in the GOOPS manual ("8.6.5 Generic Function and Method Examples"), which would be like this: (define-generic new-absolute-file-name?) (let ((old-absolute-file-name? absolute-file-name?)) (define-method (new-absolute-file-name? (f <file-name>)) (proper-list? (route f))) (define-method (new-absolute-file-name? (f <string>)) (old-absolute-file-name? f))) (set! absolute-file-name? new-absolute-file-name?) That works, but as you rightly point out, that rebinds the symbol outright and thus doesn't even require it to be exported from the module. So, that won't play nicely with others. I can try to take what you wrote very literally: > If you must override core procedures, then please use #:export and > #:replace in the 'define-module' form, and simply 'define' the new > binding in your module instead of using 'set!'. That way, the bindings > in (guile) will be left unchanged, and your new bindings will only be > used in modules that import your module. (define-module (file-names) ... #:export (absolute-file-name? ...) #:replace (absolute-file-name?)) (define-generic new-absolute-file-name?) (let ((old-absolute-file-name? absolute-file-name?)) (define-method (new-absolute-file-name? (f <file-name>)) (proper-list? (route f))) (define-method (new-absolute-file-name? (f <string>)) (old-absolute-file-name? f))) (define absolute-file-name? new-absolute-file-name?) ...i.e. just changing set! to define. However, that gives me the same "Unbound variable" compile-time error as above. I'm clearly missing something obvious and I have no idea how to proceed. GOOPS isn't behaving the way I would expect based on the manual: -- syntax: define-generic symbol Create a generic function with name SYMBOL and bind it to the variable SYMBOL. If SYMBOL was previously bound to a Scheme procedure (or procedure-with-setter), the old procedure (and setter) is incorporated into the new generic function as its default procedure (and setter). Any other previous value, including an existing generic function, is discarded and replaced by a new, empty generic function. The procedure is written in Scheme, not C (in ice-9/boot-9.scm), so I don't expect to have to treat it specially in any way like primitives might require. So, I feel like I'm blindly trying to get things to work without understanding what's happening under the hood. That's not the right way to go about things. So, how does one provide a module that replaces symbols for built-in procedures with generic functions, such that these generics provide both specialized methods and a default function using the original procedure? Thanks for your help, -brandon ps - You say that I should use #:export and #:replace, but according to the manual, #:replace "[exports] all identifiers in LIST ... and mark[s] them as “replacing bindings”." So, shouldn't be unnecessary to put the symbol in both lists?