Jim Lynch Codes
  • Blog
  • About Jim

Writings about one coder's stories & experiences.

A Brief Guide To ClojureScript REPLs & Namespaces

11/23/2017

0 Comments

 
Today is Thanksgiving, and as we close out 2017 currently especially thankful for all of these great programming languages and tools that have been created and shared. It is really incredible that anyone with (admin) access to a computer can get started with any programming language literally right now. It's just a google away. ;) Anyway, since you've come to this post I'll assume you're interested in using ClojureScript, and I won't have to bore you with how amazingly awesome and mind-expanding learning ClojureScript is because of how data-focused and simple your code becomes without the overhead of modern OOP imperative syntax. So, hold onto your keyboards because in this post I'll show you that it's not hard at all to get started with ClojureScript! 

Command Line Time!

That's right, folks. We're bootin' up that good ole' matrix-lookin, dos-era hacker window. If you're on Mac or Linux I'm referring to the terminal application. On windows you can use the linux subsystem shell (windows 10+), powershell, or cmd (with or without mingew).  

Download a Clojurescript REPL

My top three (there may be others):
  • lumo
  • planck
  • lein
In addition to providing a ClojureScript REPL these command line tools can scaffold out new projects, pull dependencies from cljsjs, and all sorts of other fun and magical things. I've linked to each of these programs in the bullet list above. I know it can be difficult sometimes to download them, but please do not give up! Everyone should experience the magic of the ClojureScipt REPL, and it's not the same to just read this article without following along. 

A Basic ClojureScript File

Now, let's create a ClojureScript file so that we can load it into the REPL! Create a file named main.cljs, and type the code below into it. You can use any editor really, although you may need to install some ClojureScript-specific plugins to get nice pretty syntax highlighting. Some popular editors are Emacs, Vim, Intellij, WebStorm, Atom, VS Code, and Sublime.
(ns main)

(defn derp []
  (println "derping...")
  "derp")
This code creates a namespace named "main" that contains a function named "derp" which prints the text derping... to the console and returns the string "derp". It's important that the namespace is the same as the file name. As a Clojure rule of thumb each file should only have one namespace, and everything defined in that file lives within the namespace.  
One you've got that file name saved, navigate in your terminal to the directory in which you created the file. Then boot up your favorite REPL using such commands like lumo, planck, or lein trampoline cljsbuild repl-listen.​ 
Picture

Requiring Your File

Alright, now after calling one of the above commands you should have a prompt with an arrow which means that the REPL is ready for you to enter stuff! Now, in order to load our main namespace we can use the require command. So, let's jsut naively just try to require main like this:
(require main)
;; => Arguments to require must be quoted.
Then we get an error, "Arguments to require must be quoted". Alrighty then! It you really think about it then it kind of intuitively makes sense that you would have to quote your namespaces because if you didn't then the REPL would interpret it as a symbol, and we have not defined any symbol called "main". Anyway, let's throw in a quote and see what happens! 
(require 'main)
;; => nil
And to this my REPL responds with "nil". This is a good thing! The require function returns nil so this is expected. It doesn't necessarily mean that your namespace was added properly, buy hey, it's better than a stack trace of errors!
Ok, now let's test to see if it worked by calling the function derp ​that we defined in the file.
(main/derp)
;; => derping...
;;    "derp"
Notice that even though we required the namespace we still need to refer to the namespace every time we want to use a function from that namespace, and we would then join them together with a backslash character  "/"  in between.

Require Files In Other Folders

Interestingly, a quirk of ClojureScript namespaces is that all "-" characters in the namespace are interpreted as "_" in the file system names, and folder separation is represented by a "." character. So if my directory structure looked like this:
Picture
(ns some-folder.some-file)

(defn something []
  (println "hey")
  42)
Then I could name my namespace "some-folder.some-file" or "some_folder.some_file". However, I cannot name my folders or files with a "-" and refer to them! If I type "-" it is interpreted as "_", and if I type "_ it is interpreted as "_"! The key lesson here is that in ClojureScript you should not use dashes in the file or folders names. Use underscores to separate words in folder and file names, and use dashes only for namespaces (where the dashes occur where the underscores are in the filepath).   
Let's see it in action, shall we? So, I navigate in my command line to the root folder in the image above and start up my REPL. Then I type this:
(require 'some-folder.some-file)
;; => nil
With this we have added the name space some-folder.some-file from the file some_file.cljs located in the folder some_folder. Notice that the repl doesn't really just add everything in the namespace automatically. You still need to refer to the entire namespace when calling a function.  
(something)

;; => WARNING: Use of undeclared Var cljs.user/something at line 1 
;;    Cannot read property 'call' of undefined
Whoops, forgot the namespace! Let's try this:
(some-folder.some-file/something)
;; => hey
;;    42
Writing out this, as we say, fully qualified namespace, can get pretty monotonous after like 1 time so we can refer to it as another name by passing to the require function a quoted vector with the :as ​macro like this: 
(require '[some-folder.some-file :as file])
;; => nil
And you can now call functions from that namespace like this:
(file/something)
;; => hey
;;    42

Files Requiring Files

Now let's get a bit more advanced. Suppose our directory structure now looks like this:
Picture
Our "other_file" contains a namespace other-folder.other-file with a function sayHey. 
(ns other-folder.other-file)

(defn sayHey []
  (println "Hey there 'errbody!"))
Our "nested_folder_file" has a similar namespace and a sayHey function. Notice that the namespace for each file is relative to the root of the project.
(ns some-folder.nested-folder.nested-folder-file)

(defn sayHey []
  (println "Hey, I'm the nested file."))
We can then modify our "some_file" to load these other namespaces and call their functions like so:
(ns some-folder.some-file
  (:require [other-folder.other-file :as other]
            [some-folder.nested-folder.nested-folder-file :as nested]))

(defn sayHeyOther []
  (other/sayHey))

(defn sayHeyNested []
  (nested/sayHey))
Now let's boot up our REPL! Interestingly, our trusy "require" method won't prove too useful here since it does not load the sub-requires. Instead, we shall use in-ns (to tell the REPL to be "in the namespace"). Here's an example of how you can use in-ns.​
(in-ns 'some-folder.some-file)
;; => nil
(sayHeyOther)
;; => Hey there 'errbody!
(sayHeyNested)
;; => Hey, I'm the nested file.

Now Go Make Cool Functions!

If you're new to ClojureScript and the REPL then I hope you learned something here. With this power you can begin to write code that uses modular functions to manipulate data which is at the core of what Clojure and ClojureScript are all about. Stay tuned for more blog posts where I'll show you how to use leiningen as a build tool, import cljsjs and pure javascript libraries, and even build AWS lambda functions with ClojureScript! I wish you good luck hope you have fun with it!
0 Comments

Your comment will be posted after it is approved.


Leave a Reply.

    ​Author

    Picture
    The posts on this site are written and maintained by Jim Lynch. About Jim...
    Follow @JimLynchCodes
    Follow @JimLynchCodes

    Want FREE access to
    my daily stock tips 
    ​newsletters??
    Sign up here:

    - Triple Gainers
    - Rippers N' Dippers
    - Growingest Growers
    ​

    Categories

    All
    Actionscript 3
    Angular
    AngularJS
    Automated Testing
    AWS Lambda
    Behavior Driven Development
    Blogging
    Business Building
    C#
    C / C++
    ClojureScript / Clojure
    Coding
    Community Service
    CS Philosophy
    Css / Scss
    Dev Ops
    Firebase
    Fitness
    Flash
    Front End
    Functional Programming
    Git
    Go Lang
    Haskell
    Illustrations
    Java
    Javascript
    Lean
    Life
    Linux
    Logic Pro
    Music
    Node.js
    Planning
    Productivity
    Professionalism
    Python
    React
    Redux / Ngrx
    Refactoring
    Reusable Components
    Rust
    Security
    Serverless
    Shell Scripting
    Swift
    Test Driven Development
    Things
    TypeScript
    Useful Sites
    Useful Tools
    Video
    Website Development
    WebStorm
    Writing

    Archives

    February 2021
    January 2021
    October 2020
    September 2020
    May 2020
    April 2020
    February 2020
    January 2020
    December 2019
    October 2019
    September 2019
    August 2019
    July 2019
    June 2019
    May 2019
    April 2019
    March 2019
    February 2019
    January 2019
    December 2018
    November 2018
    October 2018
    September 2018
    August 2018
    June 2018
    May 2018
    April 2018
    March 2018
    February 2018
    January 2018
    December 2017
    November 2017
    October 2017
    September 2017
    August 2017
    July 2017
    May 2017
    April 2017
    March 2017
    February 2017
    January 2017
    December 2016
    November 2016
    October 2016
    September 2016
    August 2016
    July 2016
    June 2016
    May 2016
    April 2016
    March 2016
    February 2016
    January 2016
    December 2015
    November 2015
    October 2015

    RSS Feed

  • Blog
  • About Jim
JimLynchCodes © 2021