Question

Various Clojure style guides recommend avoiding lines longer than 80 characters. I am wondering if there is an idiomatic way to avoid long String literals.

While it's common these days to have wide screens, I still agree that long lines should be avoided.

Here are some examples (I'm tempted to follow the first):

;; break the String literal with `str`
(println (str
    "The quick brown fox "
    "jumps over the lazy dog"))

;; break the String literal with `join`
(println (join " " [
    "The quick brown fox"
    "jumps over the lazy dog"]))

I am aware that Clojure supports multi-line String literals, but using this approach has the undesired effect of the newline characters being interpreted, e.g. using the repl:

user=> (println "The quick brown fox
  #_=>   jumps over the lazy dog")
The quick brown fox
  jumps over the lazy dog
Was it helpful?

Solution

You should probably store the string inside an external text file, and read the file from your code. If you still feel the need to store the string in your code, go ahead and use str.

EDIT:

As requested, I will demonstrate how you can read long strings at compile time.

(defmacro compile-time-slurp [file]
  (slurp file))

Use it like this:

(def long-string (compile-time-slurp "longString.txt"))

You may invent similar macros to handle Java Properties files, XML/JSON configuration, SQL queries, HTML, or whatever else you need.

OTHER TIPS

I find it convenient to use str to create strings and use character literals such as \newline or \tab instead of "\n" to break them. I rarely violate the 80-column rule this way.

The most idiomatic ways I know of are the following:

1) Use (str) to split the string over multiple lines.

(str "User " (:user context)
     " is now logged in.")

This is probably the most idiomatic usage. I've seen this done in multiple libraries and projects. It is fast, since (str) uses a StringBuilder under the hood. It also allows you to mix code in transparently, as I've done in the example.

2) Allow strings to break the 80 char limit by themselves, when it makes sense.

(format
  "User %s is now logged in."
  (:user context))

Basically, it's ok to break the 80 char limit for strings. Chances are it's less likely you care about reading the string when you work with the code, and on the off chance you need to, exceptionally, you'll need to scroll horizontally.

I've wrapped the string in a (format) here to be able to inject code similarly to my previous example. You don't need to.


Less idiomatic ways would be:

3) Put your strings in files and load them from there.

(slurp "/path/to/userLoggedIn.txt")

With a file: /path/to/userLoggedIn.txt containing:

User logged in.

I advise against this because:

  • It introduces IO side effects
  • It has the potential to fail, say the path is wrong, the resource is missing or corrupted, the disk errors, etc.
  • It has performance implications, disk reads are slow.
  • Its hard to inject content from code if you need too.

I would say do this only if your text is really big. Or if the content of the string needs to be changed by non devs. Or if the content is obtained externally.

4) Have a namespace where you def all your strings in, and load them from there.

(ns msgs)
(defn logged-in-msg [user]
  (format
"User %s is now logged in."
    user))

Which you then use like this:

(msgs/logged-in-msg (:user context))

I prefer this over #3. You still need to allow to use #2 here, where it's ok to have strings break the 80 char limit. In fact, here you put strings by themselves on a line, so they are easy to format. If you use code analysis like checkstyle, you can exclude this file from the rule. It also does not suffer from the issues of #3.


If you are going with #3 or #4, you probably have a special use case for your strings, like internationalization, or having business edit them, etc. In those cases, you might be better served building a more robust solution, that could be inspired from the above methods, or using a library that specializes in those use cases.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top