Kyle’s entire series on Clojure from the ground up is really good. Definitely worth reading if you’re interested in learning the language.
[Comment removed by author]
I assume you’re trolling, but here are some thoughts on packaging nonetheless.
You could write an interesting paper on the drift of package communities, but my personal theory is that Clojure’s package naming conventions (short, evocative, abstract, unique), like those in Python and other modern languages, came about in response to earlier packaging traditions. In particular, there’s a split between the core.x libraries, which may be community maintained but are officially blessed by the Clojure maintainers, and the general commons, where there’s a reticence to name packages things like “file” or “oracle”. Core libraries usually have standardized, descriptive, privileged names, like “core.check”, “core.matrix”, “core.logic”, or come built into the stdlib, like “clojure.string” or “clojure.io.java”. These are roughly analogous to the role of IO::File in Ruby, or FileUtils in Ruby.
Those names are the most privileged, authoritative, and I think the community tries to steer clear of claiming those names when they aren’t sure their library is the most general or most authoritative solution. Folks are looking for words that are easy to say and type, that are unique enough to google for, and that carry some evocative meaning–all these in varying degrees, depending on personal style. This is common in Ruby, Python, CPAN, and basically every other packaging system. If you think CPAN names are universally understood, take a look at
and let me know what Mojo, Dancer, MooX, Marpa, Bubblegum, Faker, CatalystX, LucyX, and Acme-LINFIR mean. These names don’t have to be immediately meaningful to outsiders because a.) package discovery is much less frequent than package use, b.) packages in CPAN, RubyGems, Maven Central, and Clojars come with description fields, and c.) you tend to find packages via a search, not by skimming a list of package names. The commons is just too broad and too dense for everything to take place in an orderly cladistic manner.
In some cases it’s obvious that there will be only one library in a given space, especially for wrappers around other libraries. In those circumstances, you’ll often see a clj- prefix, like “clj-helix” or “clj-http”. Even then, there can be name conflicts. Cheshire, in the long run, turned out to be a better JSON parser than clj-json, and has gained widespread community traction.
Java’s approach was to fully qualify packages with domain names, which led to package names littered by non-semantic unique identifiers: “org.jboss.netty”, for instance. This solves the uniqueness constraint at the cost of longer names–and because those names reflect the organizational structure of the authors rather than the project itself, you wind up in weird circumstances sometimes. “org.eclipse” is home to all sorts of projects that have nothing to do with IDEs, and org.jboss.netty is in the midst of a prolonged, painful migration to io.netty. Naming is hard.
TL;DR, I don’t get the brogrammer comment. This is a natural outcome of a packaging ecosystem where core names are allocated by a small, slow-moving language committee, and other packages emerge from a larger, decentralized commons. Never found it to be a problem in practice, in any of the languages I work in.
As for “bolted-on typing”, there’s a long, ongoing, and productive conversation to be had about the interplay between strong, weak, static, and dynamic correctness analysis; their relationships to functional and generative testing, and tangential discussions of performance and mutability–but I don’t find your comment particularly insightful in any of those dimensions.
I can’t parse any of this in a way that makes sense. You claim that s-expressions are fundamentally incompatible with Racket’s type system, but Racket is written in s-expressions. I don’t understand how Clojure is “co-opting” Racket’s type system; it’s not like Rich Hickey has wrested control of the Racket mailing list away from the community and is steering Typed Racket into the abyss. Their type systems aren’t even all that similar, as Lisps go.
You claim that the point of a Lisp is mutation, but mutation is a.) not required for a Lisp and b.) not incompatible with strong typing. Indeed, Clojure’s type system, like many Lisps, is on the stronger side of the type spectrum. For that matter, there are plenty of strongly and statically typed languages which make much heavier use of mutation than Clojure.
It’s possible that you misapprehend the difference between strong and static typing; but that doesn’t make sense either: Lisps are amenable to static verification just like any other language family. You’re clearly aware of Typed Racket. Clojure’s core.typed enhances Clojure’s type system with strong, static, partial types, including dependent value analysis. For an even stronger static type formalism for Lisps, check out Shen, which provides rigorous proof rules for all types, including the macro system.
I don’t see what you can possible mean by any of this. First, here’s the type of trees of integers made out of s-expressions in Typed Racket:
(define-type Tree (Rec T (U Integer (Pair T T))))
So s-expressions can’t be incompatible with Typed Racket; in fact, handling them well was a primary design goal.
Second, all of modern Lisp is “written in s-expression” in the same syntactic sense that Racket is – even Lisp machines didn’t execute s-expressions.
Third, plenty of people in the Racket community use Typed Racket – see Whalesong, or the math library, or Ray Racine’s web libraries, or … Typed Clojure seems to be getting wide use as well – see, for example, CircleCI’s post about it.
Full disclosure: I created Typed Racket.