Skip to content

Instantly share code, notes, and snippets.

@telekid
Last active January 8, 2020 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save telekid/0f276bfa3b3f0d395a7a71158adbb35d to your computer and use it in GitHub Desktop.
Save telekid/0f276bfa3b3f0d395a7a71158adbb35d to your computer and use it in GitHub Desktop.
;; Spec's global ns registry makes it challenging to declare multiple instances
;; of the same concept in the same ns. For example, say I want to define specs
;; for multiple continents in (ns models.geography.continent). Different continents
;; have different animal populations, so they require different animal counts:
(ns models.geography.continent
(:require [models.animals :as animals]))
;; First, we define a spec for Antarctica:
(defn antarctica [{:keys [::animals/penguins]}])
(s/fdef antarctica
:args (s/cat :animals ::animals))
(s/def ::animals (s/keys :req [::animals/penguins]))
;; Now, if we want to do the same for Africa, we're in a bit of trouble:
(defn africa [{:keys [::animals/lions]}])
(s/def africa
:args (s/cat :animals ???))
;; ^^^
;; ::animals has already been defined.
;; One way to solve this problem is to put each continent in its own ns, e.g.
;; ˅
(ns models.geography.continent.antarctica)
(s/def ::animals ...)
;; This works, but it feels pretty heavy-handed, especially when the fn implementations
;; share a lot of references.
;; A different approach would involve a language extension:
(ns models.geography.continent
(:require [models.animals :as animals]))
;; This would allow you to extend ns aliases inline:
;; ˅
(s/def ::.africa/animals ...)
;; the above would expand to :models.geography.continent.africa/animals
;; For symmetry, it could also make sense to allow aliases to be extended this way:
::animals.penguin/weight
;; expands to :models.animals.penguin/weight
;; One downside of this language modification is that it promotes ad-hoc creation of
;; namespaces, which could theoretically become hard to reason about.
;; (The other obvious downside is... language modification.)
;; I'm curious how other people approach this problem?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment