Oskar Skuteli
Oskar Skuteli

Reputation: 658

What is the naming convention for a single var namespace in clojure/clojurescript?

I often find myself defining namespaces in clojurescript that contain only a single var created via def or defn that I'll be using outside of that namespace.

This is especially common when using , where I define my components in separate files/namespaces and I only ever use these single components outside the namespace.

(ns project.components.component-name)
(defn component-name ...)

So I import them this way, and I find it pretty repetitive and unclear as there is one name used for both namespace and component:

project.components.component-name :as [component-name]

component-name/component-name

or inferior :refer (because it's less obvious that var come's from another namespace)

project.components.component-name :refer [component-name]

component-name

I know that there is a useful pattern for this in ECMAScript:

export default function () { ... };

So is there anything like this in Clojure? Or maybe there is some established convention for this?

Below is the convention I started to use recently and I'm very unsure about it.

(ns project.components.component-name)
(defn _ ...)

project.components.component-name :as [component-name]

Then use it as

component-name/_

Upvotes: 1

Views: 275

Answers (2)

Tim X
Tim X

Reputation: 4235

I'm not sure one component per namespace is the best approach. This will result in a large number of namespaces and considerable repetition. However, this is clojure and everyone has a different style. My approach is to use the namespaces to break up things along functionality. With all but the vary simplest components, I find it vary rare that a component won't also use other components. I will tend to group together all the components used in a particular function and for vary low level components which are used in most other components, have a /utility/ or /base/ namespace. For example, I might have something like

project --|
          src --|
                my-app --|
                         core.cljs
                         interface --|
                                     base.cljs
                                     navbar.cljs
                                     sidebar.cljs
                                     tabber.cljs

In each of those namespaces, there may be multiple components. Some of them may be defined as private to that namespace and others are the entry component which is referenced by core.cljs. I find namespace require sections don't get too large or repetitive and I don't need to jump around in different files as much YMMV.

Upvotes: 1

James Conroy-Finn
James Conroy-Finn

Reputation: 343

An underscore is typically used for a value you don't care about in Clojure so I'd strongly suggest you avoid use of _ as a function name. For example, you'll often see code in the wild like this:

;; Maybe when destructuring a let. Kinda contrived example.
(let [[a _ _ d] (list 1 2 3 4)]
   (+ a d 10))

;; Quite often in a protocol implementation where we don't care about 'this'.
(defrecord Foo []
  SomeProtocol
  (thing [_ x]
    (inc x)))

There's nothing wrong with having a single var in a namespace, although I would probably only introduce a namespace when there's a reasonable chunk of functionality. You could try a namespace like my-app.components where you keep all the little bits until they're big enough to warrant a dedicated space. Something along the lines of this:

(ns my-app.components
  ;; The profile stuff is really big lets say.
  (:require [my-app.components.profile :as profile]))

(defn- items->ul
  [items]
  [:ul (map #(vector :li (:text %)) items)])

(defn- render-nav
  [state]
  [:nav (-> state deref :nav-items items->ul)])

(defn- render-footer
  [state]
  [:footer (-> state deref :footer-items items->ul)])

(defn render-layout
  [state]
  [:html
   [:head [:title (:title @state)]]
   [:body
    [:main
     (render-nav state)
     (profile/render-profile (-> state deref :current-user))
     (render-footer state)]]])

Upvotes: 1

Related Questions