> Given that the program-arity / program-arities is documented, the more
> pressing problem is that programs using it would be broken right now.
> People may be holding off from updating Guile because they don’t have
> the time to investigate breakage in programs that are working perfectly
> fine in the old version. Which is the typical case for useful tools.
> 
> The worst user experience is seeing a working program break when
> updating a dependency: if the docs are wrong, you’re still in the
> context of your tool, but if it breaks on update, all that context has
> been flushed out already — often years ago.

Fair point. A lot of projects transition APIs by providing deprecation notices, 
but I am not aware of Guile doing that for this API. This is a strong argument 
against removing it immediately.
 
> Is it viable to wrap the procedure and exactly preserve the API, so
> existing programs keep working? If it’s a bit slower, that should not
> cause pain (because hardware and Guile got faster in the meantime) but
> it should not break.

I believe this is possible so long as these programs do not need to access 
arity information from procedures which pass the "primitive-code?" predicate. I 
am not sure what this predicate is actually testing. The implementation of 
"is_primitive_code" in "libguile/programs.c" is looking at a list of 
"code_arena" structs which I am not familiar with. The implementation of 
"find-program-arities" in "module/system/vm/debug.scm" is searching through 
loaded ELF images to find the one which contains the given program (and always 
fails to find one when the program passes "primitive-code?"). Based on the 
commit message in 27337b6373954e1a975d97d0bf06b5c03d65b64d, it seems like this 
behavior is expected. What puzzles me the most is that functions defined at the 
scheme level in the same file are not consistent in whether or not they are 
primitive. For example, "count" in SRFI 1 is primitive but "unzip1" is not. My 
best guess is that it has something to do with JIT compiled functions, but that 
truly is a guess.

Also, I have not looked at the output of "arity:start" and "arity:end". I'm not 
sure how I would go about testing these, but it looks like the struct returned 
from "find-program-arities" contains the same information. This procedure also 
has an optional "context" argument; I have only tried using the default value.

This is the code I'm currently using to try things out. The final line produces 
a lot of output, you can just comment it out for a quieter script.

(use-modules (system vm debug) (system vm program))

(define program-module (resolve-module '(system vm program)))

(module-set! program-module 'program-arities
  (compose find-program-arities program-code))

(module-set! program-module 'arity:start             arity-low-pc)
(module-set! program-module 'arity:end               arity-high-pc)
(module-set! program-module 'arity:nreq              arity-nreq)
(module-set! program-module 'arity:nopt              arity-nopt)
(module-set! program-module 'arity:rest?             arity-has-rest?)
(module-set! program-module 'arity:kw                arity-keyword-args)
(module-set! program-module 'arity:allow-other-keys? arity-allow-other-keys?)

(define* (uut req #:optional opt0 opt1
                  #:key key0 key1 key2
                  #:allow-other-keys
                  #:rest rest)
  (cons* req opt0 opt1 key0 key1 key2 rest))

(define arities (program-arities uut))
(define arity   (program-arity uut #f))

(format #t "Number of arities:  ~s~%" (length                  arities))
(format #t "Required arguments: ~s~%" (arity:nreq              arity))
(format #t "Optional arguments: ~s~%" (arity:nopt              arity))
(format #t "Rest argmuent?      ~s~%" (arity:rest?             arity))
(format #t "Keyword arguments:  ~s~%" (arity:kw                arity))
(format #t "Other keys?         ~s~%" (arity:allow-other-keys? arity))
(newline)

(define uut
  (case-lambda
    ((single) single)
    ((du o) (list du o))
    ((tr i o) (list tr i o))))

(format #t "Arities from a case-lambda: ~s~%" (length (program-arities uut)))
(newline)

(define (generate-arity-trier proc)
  (lambda (sym var)
    (let ((val (variable-ref var)))
      (when (procedure? val)
        (format #t "Arities of ~s: ~s~a~%"
                sym
                (and=> (proc val) length)
                (if (primitive-code? (program-code val)) " (primitive)" ""))))))

; use any of the below procedures in module-for-each line at the end
(define try-program-arity (generate-arity-trier program-arities))
(define try-program-arguments-alist (generate-arity-trier 
program-arguments-alist))

(define (check-for-inconsistency sym var)
  (let ((val (variable-ref var)))
    (when (and (procedure?      val)
               (program-arities val)
               (primitive-code? (program-code val)))
      (format #t "~s is inconsistent!~%" sym))))

(module-for-each try-program-arity (resolve-interface '(srfi srfi-1)))


  • Removing program-... Developers list for Guile, the GNU extensibility library
    • RE: Removing... Maxime Devos
      • RE: Remo... Developers list for Guile, the GNU extensibility library
        • RE: ... Developers list for Guile, the GNU extensibility library
          • ... Dr. Arne Babenhauserheide
            • ... Developers list for Guile, the GNU extensibility library
            • ... Developers list for Guile, the GNU extensibility library
          • ... Maxime Devos
            • ... Developers list for Guile, the GNU extensibility library

Reply via email to