Portability of ns keywords

I’m hoping that someone here might know a good solution or tell me I’m wrong, but otherwise here goes for a conversation starter:

Namespaced keywords seem like a great idea in theory, but are not portable (not even within Clojure). Current working example: I have a map representing a student registration. Now, what I’d like to have is this:

{:student/id "23457y89i"
 :proctor/id "3"
 :language/native "English"
 :language/test "Spanish"
;; and so on
}

However, I run in to two problems: first, this is being submitted by a web front-end as json, so I can’t expect keywords to survive the trip intact. Second, even within clojure apps, destructuring with ns keys seems problematic:

{:keys [student/id proctor/id] ;; breaks or results in just one var `id, because namespacing on symbols isn't as virtual as namespacing on keywords

If I’m lucky someone can tell me why I’m wrong, or at least offer a different solution than getting into the habit of structuring my maps as if ns keywords don’t exist:

{:student {:id "23457y89i"}
 :proctor {:id "3"}}

;; OR
{:student-id "23457y89i"
 :proctor-id "3"}
1 Like

To learn how to deal with namespace conflicts in keys destructuring, see the Namespaced keys section here: https://clojure.org/guides/destructuring

For JSON roundtrips, you’ll need to create a custom scheme with your serializer. Like turn “/” into “_” or some sort. This guide has suggestions for it: https://purelyfunctional.tv/mini-guide/json-serialization-api-clojure/

Also see this old clojureverse convo around it: Should we really use Clojure's syntax for namespaced keys?

2 Likes

:keys is a shortcut that probably isn’t meant for what you’re trying to do. You can always use the “longer” form of map destructuring. You’re going to have to specify renames for the keys anyway if you’re going to use them in the same scope.

(let [m {:student/id      "23457y89i"
         :proctor/id      "3"
         :language/native "English"
         :language/test   "Spanish"}
      {sid :student/id
       pid :proctor/id
       :language/keys [native test]} m]
  [sid pid native test])

Wow! I had no idea you could do that :language/keys trick

In the past, I’ve seen a DSL for dealing with Json. I don’t know if there are any high quality libraries. I don’t think I could tell. I don’t have much Json experience. You might try searching for something like that.

I’d consider splitting handling up into two functions, where each function destructures the keys it requires. This sounds like a case for separation of concerns.