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!
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).
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.
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.
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.
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:
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!
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.
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.
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:
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:
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.
Whoops, forgot the namespace! Let's try this:
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:
And you can now call functions from that namespace like this:
Now let's get a bit more advanced. Suppose our directory structure now looks like this:
Our "other_file" contains a namespace other-folder.other-file with a function sayHey.
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.
We can then modify our "some_file" to load these other namespaces and call their functions like so:
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.
The posts on this site are written and maintained by Jim Lynch. About Jim...