Hi Alex, Thank you for the work you've already put in to improving docstrings in Clojure 1.9, I noticed a bunch of docstring Jiras land recently which is really encouraging.
Specs certainly helps those of us who are familiar with Clojure and clojure.spec already, and know how to use specs to generate examples. However, as they are currently presented, clojure.spec is incredibly beginner-hostile in a way that docstrings aren't. It would be interesting to see if the docstrings presented by tooling, the various documentation websites, and so on could be augmented by clojure.spec. I do not see how that augmentation would remove the need for a clearly worded and complete docstring. There is also a very important case that I don't think clojure.spec addresses at all, which is the the ways that functions fail. I haven't come across a way to specify exception behaviour with clojure.spec which is just as important as documenting the "happy path" behaviour. Thanks for listening -Gordon On Monday, 25 September 2017 23:15:45 UTC+1, Alex Miller wrote: > > > > On Monday, September 25, 2017 at 11:42:12 AM UTC-5, Phillip Lord wrote: >> >> >> >> Clojure's doc strings, though, contain knowledge that is not >> clear. Consider, this documentation: >> >> Returns a new seq where x is the first element and seq is the rest. >> >> x is the name of a parameter. So is the the second occurence of seq, but >> not the first. Neither first, nor rest refer to the functions in >> clojure.core, although both probably should do. >> > > You didn't mention it but this is the docstring for cons. You also > stripped half the context (the arglist): > > ------------------------- > clojure.core/cons > ([x seq]) > Returns a new seq where x is the first element and seq is > the rest. > > To me, first and rest here are clearly referring to the English meaning, > not the functions, but also intentionally echoes the actual function names > which can be used to extract x and seq. I think that's all good. You can go > further with echoing the first/rest stuff by using a spec with a :fn too: > > ------------------------- > clojure.core/cons > ([x seq]) > Returns a new seq where x is the first element and seq is > the rest. > Spec > args: (cat :x any? :seq seqable?) > ret: seq? > fn: (fn [{:keys [args ret]}] (and (= (:x args) (first ret)) (= (sequence > (:seq args)) (rest ret)))) > > I think this is way better in specifying the args and ret and actually > includes a very precise description of how the args and return value relate > to first and ret. And you can property test it with stest/check! > > >> Compare this to the documentation for "apply" from Andy Fingerhuts >> thalia. >> > > It seems weird to me to give the docstring from cons above and then from > Andy's apply below as a comparison. > For actual comparison the docstring of apply: > > ------------------------- > clojure.core/apply > ([f args] [f x args] [f x y args] [f x y z args] [f a b c d & args]) > Applies fn f to the argument list formed by prepending intervening > arguments to args. > > > >> `f` is a function and the last argument `args` is a sequence. Calls > > this is wrong, should be something seqable --------------^ > see: (apply vector 1 "abc") ;; [1 \a \b \c] > > I do think it would be useful if the docstring for apply said that args > had to be seqable. Of course, if apply had a spec, you'd have that: > > user=> (s/fdef clojure.core/apply :args (s/cat :f ifn? :prepend (s/* any?) > :args seqable?)) > clojure.core/apply > user=> (doc apply) > ------------------------- > clojure.core/apply > ([f args] [f x args] [f x y args] [f x y z args] [f a b c d & args]) > Applies fn f to the argument list formed by prepending intervening > arguments to args. > Spec > args: (cat :f ifn? :prepend (* any?) :args seqable?) > ret: any? > > Some slight alterations in the :arglists, :doc, and spec names could align > these even better. > > `f` with the elements of `args` as its arguments. If more arguments >> `x`, `y`, etc. are specified, they are added to the beginning of >> `args` to form the complete argument list with which `f` is called. >> > > I find this confusing in that it starts with the beginning and end and > then talks about the middle and prefer the original, but matter of taste I > suppose. I'd take the spec over either. > > Examples: >> ```clojure\nuser=> (apply + [1 2]) ; same as (+ 1 2) 3 >> user=> (apply + 1 2 [3 4 5 6]) ; same as (+ 1 2 3 4 5 6) >> > > I think one example in this docstring would actually say a lot. I don't > like the formatting here (why the clojure? why the user prompt? why the > dangling 3?). Could actually use the spec to generate as many examples as > you like though using s/exercise-fn! > > user=> (s/exercise-fn 'clojure.core/cons) > ([(nil "") (nil)] > [(() "") (())] > [(nil nil) (nil)] > [(nil {Hr-* -1.0, false #uuid "bf1314cc-f950-4a52-969b-45023fc5cd13"}) > (nil [Hr-* -1.0] [false #uuid "bf1314cc-f950-4a52-969b-45023fc5cd13"])] > > etc etc - make as many as you like. You would want to format these instead > (bike shed away): > > (cons nil "") ;; => (nil) > (cons () "") ;; => (()) > (cons nil nil) ;; => (nil) > etc > > >> >> Which is essentially superior in every way. > > > Other than being wrong and poorly formatted and not data and not property > testable and not able to generate infinite examples. > > >> The existence of neither specs nor clojure.org don't really change this. >> > > Wrong! See above. :) > > >> It would be possible to go even further than this; consider the runnable >> doc strings of rust -- the examples are also tests. Emacs' dash.el does >> the same thing. >> > > Cool idea. As I showed above, we're 95% of the way there already, but with > *automatically generated examples*. Although hand-picked ones would > undoubtedly serve as better examples, but you could actually inject custom > arg generators to even handle that. > > >> Still, it's been this way since I first started using clojure (1.3/1.4) >> so I suspect that it's not going to change. >> >> Phil >> >> >> >> Stuart Halloway <stuart....@gmail.com <javascript:>> writes: >> >> > Clojure has great data, and great metadata. Documentation strings are >> *not* >> > great data, they are strings. >> > >> > If you want to provide more structured support than docstrings to help >> > someone use Clojure, look at specs for inspiration. They are made of >> data, >> > and they live in a registry separate from Clojure's var system. This >> kind >> > of decoupling supports composition and tooling without requiring any >> > addition or change to Clojure. >> > >> > I would also echo Matching Socks: Having more and better guides at >> > clojure.org would be great. The contribution process is described at >> > >> https://github.com/clojure/clojure-site/blob/master/content/community/contributing_site.adoc >> >> > . >> > >> > Regards, >> > Stu >> > >> > On Mon, Sep 11, 2017 at 5:23 AM, Matching Socks <phill...@gmail.com >> <javascript:>> >> > wrote: >> > >> >> I am not convinced I would have found the API docs on reducers or >> zippers >> >> more informative if all references had been tidily markdown'ed. >> >> >> >> The new clojure.org welcomes contributions of topical overviews. >> That's >> >> helpful. >> >> >> >> But, to interpret docstrings, nothing helps like perspective. The >> thing >> >> about perspective is that there could be so many. I like "Clojure >> >> Programming" by Emerick, Carper & Grand. >> > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.