Alex gave you a correct (but fairly short) answer. I’d like to expand on it a bit, partly in light of a certain recent blog post, partly because of a personal “hot button”…
This is going to be along the same lines as clojure.set functions producing “garbage” output if you give them “garbage” input (not sets). This is the classic computer science “undefined” behavior that we see in many other languages, where the behavior is only defined for the specific types of inputs. I would _love_ all the clojure.string functions to be defined for nil as an input – since we have (str nil) => “” – but adding that nil check, or even calling str directly in clojure.string functions, adds quite an overhead for all uses (so that proposal would never be accepted). Looking at the clojure.string namespace docstring, it is explicit about nil arguments: “passing nil will result in a NullPointerException unless documented otherwise.” This makes me sad ☺ It’s almost my only source of NPEs in my Clojure code and I pretty much always want the empty string behavior in case of nil. Oh well. The docstring also has this to say about argument types: “When a function is documented to accept a string argument, it will take any implementation of the correct *interface* on the host platform. In Java, this is CharSequence, which is more general than String. In ordinary usage you will almost always pass concrete strings.” That explains why it calls toString() – to convert CharSequence (or any of its implementations) to String. Unfortunately, much as with clojure.set functions, if you pass any argument that is not an implementation of CharSequence but happens to support toString() – which is nearly anything – then you get “garbage” out because you passed “garbage” in. I think everyone passes a non-string value to a clojure.string function at least once and then scratches their head at the bizarre result (which often pops up a long way down the chain of string manipulation and therefore some distance from the bug). It’s the price we pay for improved performance in the “correct” use cases ☹ As for blank? Yes, that seems like the docstring needs correcting since it returns “True if s is falsey (nil or false), empty, or contains only whitespace.” Sean Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ "If you're not annoying somebody, you're not really alive." -- Margaret Atwood On 6/21/16, 11:24 AM, "Elena Machkasova" <clojure@googlegroups.com on behalf of ele...@morris.umn.edu> wrote: Greetings, I was looking at clojure.string functions, and noticed that some have unexpected (especially for less experienced programmers) behavior on non-string arguments. For instance, 'capitalize' applies toString to its argument, effectively making it possible to pass any type, but with unexpected results. Here are some examples that may be really confusing to novices, especially since it's not immediately obvious that the argument is returned as a string when it's printed back: (str/capitalize [\a \B \c]) ; returns "[\a \b \c]" (str/capitalize (char-array "aBc")) ; returns the address, as a string Interestingly, 'reverse' doesn't allow non-string arguments since it uses a StringBuilder, and not toString, to create a string, and there are a few other clojure.string functions that behave like 'reverse' in this regard. As a minimum, this is inconsistent with 'capitalize'. As a separate issue, blank? returns 'true' when passed 'false' (since the check is for false, not specifically for nil), but (blank? true) is a type error. It is fairly easy for experienced programmers to understand what's going on by reading the source code, but none of these behaviors are documented, and would confuse beginners. Is there anything that I am overlooking in these design decisions, or should this implementation be changed? Thanks! Elena -- 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. -- 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.