Skip to content

Incorrect :arglists, embellishment in the README, and nonstandard clojure.core/sigs breaking on Babashka #24

@edenworky

Description

@edenworky

So, the README claims that this:

(defun say-hi
  ([:dennis] "Hi,good morning, dennis.")
  ([:catty] "Hi, catty, what time is it?")
  ([:green] "Hi,green, what a good day!")
  ([other] (str "Say hi to " other)))

Should expand to this:

(defn
 say-hi
 {:arglists '([& args])}
 [& args#]
 (clojure.core.match/match
  [(vec args#)]
  [[:dennis]]
  (do "Hi,good morning, dennis.")
  [[:catty]]
  (do "Hi, catty, what time is it?")
  [[:green]]
  (do "Hi,green, what a good day!")
  [[other]]
  (do (str "Say hi to " other))))

However, as the defun macro definition confirms, this isn't actually how the code works, and the code in fact expand to:

(def say-hi
 (fun
   ([:dennis] "Hi,good morning, dennis.")
   ([:catty] "Hi, catty, what time is it?")
   ([:green] "Hi,green, what a good day!")
   ([other] (str "Say hi to " other))))

Or more fully:

(def say-hi
 (fn fn__13414
  ([G__13416]
    (let [placeholder13415 placeholder]
      (match
        [G__13416]
        [:dennis]
        (do "Hi,good morning, dennis.")
        [:catty]
        (do "Hi, catty, what time is it?")
        [:green]
        (do "Hi,green, what a good day!")
        [other]
        (do (str "Say hi to " other)))))))

Notably, defun only wraps an (anonymous) fun, and manually runs vary-meta and sets :arglists by using a private undocumented clojure.core/sigs function. However, this sigs function, for the provided say-hi, gives an :arglists of ([:dennis] [:catty] [:green] [other]), which seems to work well enough, but isn't the [& args] described in the README, but that's good, since [& args] is too generic and lends itself poorly to static analysis and automatic currying and so forth. The appropriate :arglists in this case, I believe (as this is nonstandard and undocumented), should be simply ([other]).

So first of all and certainly, the README should be updated to reflect the state of the code, because no one should use defun and expect an [& args] :arglists value. But speaking more generally, it seems to me like the sigs we get could easily be post-processed to be more compliant quite simply, by removing all non-symbol values and unifying signatures per-arity looking for a non-'_ value if one is available. I'm not sure if this is the best approach to go with (and it does add (yet more) processing at macro-time), but I submitted a PR #25 with this post-processing included, as well as updates to the tests (which don't currently check :arglists at all), and the README, and will keep an updated version on wizard-enterprises/defun where I also updated the project dependencies and added a deps.edn file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions