Are private namespaces typically respected?

Playing with core.async, I quickly found the need for a chan? predicate. Evidently this is a longstanding suggestion and it seems that the recommendation is to simply build your own based on the relevant protocols. This is, in fact, what Cognitect’s own Pedestal does. The only catch is that the protocols in question are under clojure.core.async.impl, which is not part of the official API documentation.

I gather that long-term backward compatibility is a hallmark of the Clojure ecosystem (and a big selling point as far as I’m concerned), so perhaps the lack of documentation is considered no more than a minor oversight. Is this example an anomaly, or is it just common in the Clojure world to be casual about the distinction between public APIs and private implementation details?

I would definitely say it isn’t “common” but it does happen. clojure.tools.logging is another example where the impl namespace leaks out in public because the way to override that library’s selection of a logging framework is to use a JVM option that includes the full name of a symbol in the impl namespace:

-Dclojure.tools.logging.factory=clojure.tools.logging.impl/log4j2-factory

At this point, given the public usage for both those libraries’ impl code, I very much doubt a future version of either would break that usage – per Clojure’s general principle of encouraging library maintainers to perform only accretive and fixative changes (unless they provide new names – for functions and/or namespaces – alongside the existing names).

That said, c.t.l does document the impl namespace clojure.tools.logging - tools.logging API documentation and indicates that the namespace can be used by people wishing to implement support for new logging frameworks.

And even though core.async does not document the impl namespaces, if you are building new abstractions and concretions on top of core.async, it is likely that you would need to rely on the protocols in those impl namespaces – this is something we do at work, to provide channel-like abstractions over other things, by implementing some of the low-level abstractions defined as protocols here core.async/protocols.clj at master · clojure/core.async (github.com).