Details
-
Type:
Enhancement
-
Status:
Closed
-
Priority:
Critical
-
Resolution: Completed
-
Affects Version/s: None
-
Fix Version/s: Release 1.9
-
Component/s: None
-
Patch:Code and Test
-
Approval:Ok
Description
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 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"}}
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
1- yes please. that's consistent with how tagged literals work.
2-
no please. that would make the proposed syntax useless for e.g. Datomic schemas, for which I think this would be a good fit to reduce noise3- yes please
4- yes please, consistency over print methods is important
no please. that would make the proposed syntax useless for e.g. Datomic schemas, for which I think this would be a good fit to reduce noise3- yes please 4- yes please, consistency over print methods is important