Clojure Journey X – Namespaces

Now that we know how to create our functions we need to understand how Clojure organizes and accesses it, this way is called namespaces.

Every good wizard has a lot of books on his bookshelf, with different magics to use in a lot of situations. Imagine a Clojure namespace as being one of your books, and each function or variable (defined with def) is written on it, when you need to use your function, you just search for it in this book and use it!

Your book (namespace) of functions to deal with strings

If you enter in your REPL, you’ll be in a “default” namespace called user, everything that you define here, we’ll be associated with this namespace.

user => (def author-name "otavio")
#'user/author-name

You may have already noticed that when we defined author-name it returned #'user/author-name, it means that you defined an author-name in the user namespace.

To create a new namespace and switch to it, you only need to type ns and a name to it, it will create (if not exists), and you can’t access values defined in other namespace directly anymore. Just like a blank book, waiting to be written.

user => (ns my-new-ns)
nil
my-new-ns => author-name
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: author-name in this context
Let’s start writing our namespaces

If you want, you can access any variable or function defined in other namespace, just typing its “full address” namespace + name.

my-new-ns => user/author-name
"otavio"

Switch between namespaces is easy, just use in-ns and pass the namespace name preceded by quote. After it, you can access the defined values of this namespace directly again.

any-ns=> (in-ns 'user)
#object[clojure.lang.Namespace 0x56317ffa "user"]
user=> author-name
"otavio"

You can always see in which namespace are you, just typing *ns* (but you can just see in your REPL too.)

Reading other books

Sometimes you as a wizard will want to read books written by other wizards, to not lose your precious time reinventing the wheel creating already existent magics.

Most languages are shipped with a lot of code that you must need, things like string operations, basic http logic, and much more. All this code is available for you, in the form of namespaces, and to use it is simple!

Famous Clojure Libs, just waiting to be used!

Every time that you create a new namespace using ns in your REPL, it will be automatically loaded on it, and you can just start using it, but this is not true while trying to access namespaces packaged in files (which will be important in the future when we start to work with multiple files in large projects).

Let’s use as an example the namespace clojure.string which contains functions to deal with common string operations, we want to use capitalize function from it! The first step is to make our REPL aware of the namespace that you want to use using the require function, passing as an argument the namespace that we want to load in our REPL, after this all functions and symbols globally defined in this namespace are available to us, just use them using its ‘full address’ namespace + name.

user => (require 'clojure.string)
nil
user => (clojure.string/capitalize "hello clojure")
"Hello lojure"

But write clojure.string every time isn’t productive, so we can use the :as keyword to create an alias to use this namespace.

user => (require '[clojure.string :as str])
nil
user => (str/capitalize "hello clojure")
"Hello clojure"

This required namespace will be available only on current namespace, if you change to other namespace, it will no longer be available.

Better now, ya? This is the Clojurist way of using external namespaces from other namespace (including libraries as we’ll see in the future).

If you want, you can also enter in the string namespaces and use functions directly, but I really don’t know why you may want to do it:

user => (require 'clojure.string)
nil
user => (in-ns 'clojure.string)
nil
clojure.string => (capitalize "hello clojure")
"Hello clojure"

Conclusions

Learn how to use namespaces is important! We did not learn how to pack namespace in files yet, but we will in the future! This knowledge is important, it will help while developing using our REPL, and in the future post talking about files.

Next steps

On the next post of this series, we’ll still talking about functions, with just a short trick to make our functions better and readable!

Final thought

If you have any questions that I can help you with, please ask! Send an email (otaviopvaladares at gmail.com), pm me on my Twitter, or comment on this post!

3 comments

  1. sidestep · August 30, 2021

    The mindset in clojure is that you can navigate namespaces as you would directories, so you set the curr dir with in-ns, list available symbols in there with ns-map etc. https://clojure.org/reference/namespaces#_related_functions

    Like

    • Otavio Valadares · September 5, 2021

      Very interesting! I’ll write more about this mindset in a future post talking about Clojure’s development environment, it will help a lot! Thanks for your feedback

      Like

  2. Pingback: Clojure Journey XI – Let – O. Valadares' Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s