The namespaces provide value (disambiguation) but have the downside of being repetitive and verbose.
Namespaced maps are a reader (and printer) feature to specify a namespace context for a map.
Namespaced maps combine a default namespace with a map and yield a map.
Namespaced maps are reader macros starting with #: or #::, followed by a normal map definition.
#:sym indicates that sym is the default namespace for the map to follow.
#:: indicates that the default namespace auto-resolves to the current namespace.
#::sym indicates that sym should be auto-resolved using the current namespace's aliases OR any fully-qualified loaded namespace.
These rules match the rules for auto-resolved keywords.
A namespaced map is read with the following differences from normal maps:
A keyword or symbol key without a namespace is read with the default namespace as its namespace.
Keys that are not symbols or keywords are not affected.
Keys that specify an explicit namespace are not affected EXCEPT the special namespace _, which is read with NO namespace. This allows the specification of bare keys in a namespaced map.
Values are not affected.
Nested map keys are not affected.
The edn reader supports #: but not #:: with the same rules as above.
Maps will be printed in namespaced map form only when:
All map keys are keywords or symbols
All map keys are namespaced
All map keys have the same namespace
Examples:
;; same as above - notice you can nest #: maps and this is a case where the printer roundtrips
user=> #:person{:first "Han" :last "Solo" :ship #:ship{:name "Millenium Falcon" :model "YT-1300f light freighter"}}
#:person{:first "Han" :last "Solo" :ship #:ship{:name "Millenium Falcon" :model "YT-1300f light freighter"}}
;; effects on keywords with ns, without ns, with _ ns, and non-kw
user=> #:foo{:kw 1, :n/kw 2, :_/bare 3, 0 4}
{:foo/kw 1, :n/kw 2, :bare 3, 0 4}
;; auto-resolved namespaces (will use user as the ns)
user=> #::{:kw 1, :n/kw 2, :_/bare 3, 0 4}
:user/kw 1, :n/kw 2, :bare 3, 0 4}
;; auto-resolve alias s to clojure.string
user=> (require '[clojure.string :as s])
nil
user=> #::s{:kw 1, :n/kw 2, :_/bare 3, 0 4}
{:clojure.string/kw 1, :n/kw 2, :bare 3, 0 4}
;; to show symbol changes, we'll quote the whole thing to avoid evaluation
user=> '#::{a 1, n/b 2, _/c 3}
{user/a 1, n/b 2, c 3}
;; edn reader also supports (only) the #: syntax
user=> (clojure.edn/read-string "#:person{:first \"Han\" :last \"Solo\" :ship #:ship{:name \"Millenium Falcon\" :model \"YT-1300f light freighter\"}}")
#:person{:first "Han", :last "Solo", :ship #:ship{:name "Millenium Falcon", :model "YT-1300f light freighter"}}
A common usage of namespaced keywords and symbols is in providing attribute disambiguation in map contexts:
{:person/first "Han" :person/last "Solo" :person/ship {:ship/name "Millenium Falcon" :ship/model "YT-1300f light freighter"}}
The namespaces provide value (disambiguation) but have the downside of being repetitive and verbose.
Namespaced maps are a reader (and printer) feature to specify a namespace context for a map.
Namespaced maps combine a default namespace with a map and yield a map.
Namespaced maps are reader macros starting with
#:
or#::
, followed by a normal map definition.#:sym
indicates thatsym
is the default namespace for the map to follow.#::
indicates that the default namespace auto-resolves to the current namespace.#::sym
indicates thatsym
should be auto-resolved using the current namespace's aliases OR any fully-qualified loaded namespace.These rules match the rules for auto-resolved keywords.
A namespaced map is read with the following differences from normal maps:
A keyword or symbol key without a namespace is read with the default namespace as its namespace.
Keys that are not symbols or keywords are not affected.
Keys that specify an explicit namespace are not affected EXCEPT the special namespace
_
, which is read with NO namespace. This allows the specification of bare keys in a namespaced map.Values are not affected.
Nested map keys are not affected.
The edn reader supports
#:
but not#::
with the same rules as above.Maps will be printed in namespaced map form only when:
All map keys are keywords or symbols
All map keys are namespaced
All map keys have the same namespace
Examples:
;; same as above - notice you can nest #: maps and this is a case where the printer roundtrips user=> #:person{:first "Han" :last "Solo" :ship #:ship{:name "Millenium Falcon" :model "YT-1300f light freighter"}} #:person{:first "Han" :last "Solo" :ship #:ship{:name "Millenium Falcon" :model "YT-1300f light freighter"}} ;; effects on keywords with ns, without ns, with _ ns, and non-kw user=> #:foo{:kw 1, :n/kw 2, :_/bare 3, 0 4} {:foo/kw 1, :n/kw 2, :bare 3, 0 4} ;; auto-resolved namespaces (will use user as the ns) user=> #::{:kw 1, :n/kw 2, :_/bare 3, 0 4} :user/kw 1, :n/kw 2, :bare 3, 0 4} ;; auto-resolve alias s to clojure.string user=> (require '[clojure.string :as s]) nil user=> #::s{:kw 1, :n/kw 2, :_/bare 3, 0 4} {:clojure.string/kw 1, :n/kw 2, :bare 3, 0 4} ;; to show symbol changes, we'll quote the whole thing to avoid evaluation user=> '#::{a 1, n/b 2, _/c 3} {user/a 1, n/b 2, c 3} ;; edn reader also supports (only) the #: syntax user=> (clojure.edn/read-string "#:person{:first \"Han\" :last \"Solo\" :ship #:ship{:name \"Millenium Falcon\" :model \"YT-1300f light freighter\"}}") #:person{:first "Han", :last "Solo", :ship #:ship{:name "Millenium Falcon", :model "YT-1300f light freighter"}}
Patch: clj-1910-2.patch
Screener notes:
Autoresolution supports fully-qualified loaded namespaces (like auto-resolved keywords)
TODO: pprint support for namespaced maps
TODO: printer flag to suppress printing namespaced maps