Poetry in Code

Donald Raab
7 min readJust now

--

Writing code that is poetic in nature.

Photo by Christiaan Huynen on Unsplash

Have you ever heard a developer tell you that their code reads like poetry? We are sometimes very fond of our code when we write it. What developers might mean by “code that reads like poetry” is that our code reads fluently and has good symmetry. We might make claims that our code is elegant and very readable. These are subjective measures, and not everyone will agree that something is elegant and or readable, especially if it is unfamiliar. I think most code should read like a children’s book. The code should tell you what it means and does, with very little to decipher or investigate. Code should read like a short non-fiction story. I’ve seen too far much code that reads like a murder-mystery or science-fiction thriller. Keep it simple!

There is a way that we can make our code read like poetry. We can encode actual poetry in code. I would only recommend doing this for poetry that you own or have permission to use the copyright.

Coding poetry in Java Text Blocks

Java added a neat feature called Text Blocks in Java 14. Most code examples that I have seen use text blocks for things like SQL statements. A super fun usage I have found for Java Text Blocks is coding poetry. Here’s an example of a poem I wrote in high school titled “Playing in the Sand”, stored in a static variable using a Java Text Block.

private static final String PLAYING_IN_THE_SAND =
"""
Playing in the Sand

Can one ever know the beauty
of a simple grain of sand?
Tossed about in carelessness
and sifted by someone's hand.
They're washed up on our beaches
and sent back with the tide;
The looking glass of society
reflecting the thoughts we hide.
Always felt but never seen
like something left behind;
For the individual nobody cares,
still the grains don't seem to mind.
They're the crystals of the beaches
yet treated like so much dirt;
We just shake them off our towels
and brush them off our shirts.
The kings of our children's boxes
but to us so many pawns;
We should ask ourselves this question,
would we miss them were they gone?
""";

The poem is very readable in the Java Text Block form. I am able to include the formatting as I originally intended when I wrote the poem more than three decades ago. I hope you enjoy the poem. I included the poem with some background in a blog I wrote a few years ago.

Amazingly, I had an easier time formatting that code for inclusion in Java using Text Blocks than I did formatting the poem in Medium. I had to paste a graphic to keep some of my original intended formatting, which gives clues to the reader on the cadence of the poem.

The poetry would be much less readable in the classic concatenated String style that was required prior to Java 14. Here’s the same poem using a classic String literal in Java.

    private static final String PLAYING_IN_THE_SAND =
"Playing in the Sand\n" +
"\n" +
"Can one ever know the beauty\n" +
" of a simple grain of sand?\n" +
"Tossed about in carelessness\n" +
" and sifted by someone's hand.\n" +
"They're washed up on our beaches\n" +
" and sent back with the tide;\n" +
"The looking glass of society\n" +
" reflecting the thoughts we hide.\n" +
"Always felt but never seen\n" +
" like something left behind;\n" +
"For the individual nobody cares,\n" +
" still the grains don't seem to mind.\n" +
"They're the crystals of the beaches\n" +
" yet treated like so much dirt;\n" +
"We just shake them off our towels\n" +
" and brush them off our shirts.\n" +
"The kings of our children's boxes\n" +
" but to us so many pawns;\n" +
"We should ask ourselves this question,\n" +
" would we miss them were they gone?\n";

While we can read this, we can easily be distracted from the reading and lose focus due tot the quotes, new line characters, and pluses. Java Text blocks are a great example of the Java language “getting out of our way” when coding.

The Joy of Coding Poetry

Programming is fun. Coding with poetry is also fun. It is at least fun for me. Code and poetry should leave a positive impact on the reader as well as the writer. I hope you enjoy both the code and poetry in the examples that follow.

I have written some fun code examples in tests with the “Playing in the Sand” poem. Enjoy!

Finding all the words

The first thing we can do is find all of the words in the poem and store them in a Bag. A Bag is a Collection type available in Eclipse Collections that keeps track of items and their counts. This data structure will immediately allow us to count words.

private static final ImmutableBag<String> MIXED_CASE_WORDS =
StringIterate.injectIntoTokens(
PLAYING_IN_THE_SAND,
" ,.-!;?\t\n\r\f",
Bags.mutable.<String>empty(),
MutableBag::with)
.toImmutable();

Using the StringIterate utility class in Eclipse Collections, we can quickly create a MutableBag<String> using the injectIntoTokens() method. We can then make the MutableBag<String> immutable by calling toImmutable(), which returns an ImmutableBag<String>.

Converting all the words to lowercase

We can convert all of the mixed case words to lowercase using the collect() method with a Function.

private static final ImmutableBag<String> LOWER_CASE_WORDS =
MIXED_CASE_WORDS.collect(String::toLowerCase);

Analyzing the poem

Now that we have encoded the poem in a Java Text Block and parsed all of the mixed case and lowercase words into separate ImmutableBag<String> instances, we can write some JUnit 5 unit tests to learn some things about the poem. We will use methods that all RichIterable types in Eclipse Collections understand, like size, select, reject, toSet. We will also use methods that are specific to the Bag type like selectDuplicates, selectUnique, and topOccurrences.

Count the words

The first thing we can do is count the total number of words. We can assert the expected size is 118, which should validate my word parsing logic using injectIntoTokens() is working as expected.

@Test
public void wordCount()
{
Assertions.assertEquals(118, this.getLowerCaseWords().size());
}

Find the Wordle Words

Folks might recall the Wordle craze that took the world by storm a few years ago. We can find the words that are potential Wordle words using the following code.

@Test
public void wordleWords()
{
Bag<String> words = this.getLowerCaseWords();

Set<String> wordleWords = words.asLazy()
.rejectWith(String::contains, "'")
.select(word -> word.length() == 5)
.toSet();

ImmutableSet<String> expected =
Sets.immutable.with(
"cares", "never", "would", "shake",
"boxes", "grain", "about", "glass",
"still", "kings", "brush", "pawns");
Assertions.assertEquals(expected, wordleWords);
}

We call asLazy(), which turns our Bag<String> into a LazyIterable<String>. We use rejectWith to exclude any contractions, as they are not valid Wordle words. We then use select to inclusively filter the words that have a size of five. We then convert the LazyIterable<String> that is returned to a MutableSet<String>. MutableSet<String> extends Set<String>.

Find the words that start with a capital letter

The following code will find the words in the mixed case ImmutableBag<String> that have the first letter capitalized.

@Test
public void firstUpperCaseWords()
{
Set<String> firstUpperCaseWords = this.getMixedCaseWords()
.select(each -> Character.isUpperCase(each.charAt(0)))
.toSet();

Set<String> expected =
Set.of("The", "Can", "Sand", "We", "Always", "For",
"Playing", "Tossed", "They're");

Assertions.assertEquals(expected, firstUpperCaseWords);
}

We use select() to filter those words that have their first character capitalized. This returns an Bag<String> since we call the method select() on a Bag<String>, which is what getMixedCaseWords() returns. If we changed the return type of getMixedCaseWords() to ImmutableBag<String>, then select() would have returned an ImmutableBag<String>.

Find duplicate words

The following code will find the words that have duplicates. We assert that the word counts of the resulting Bag<String> that is returned from the selectDuplicates() method call equals the expected Bag<String> in the unit test.

@Test
public void duplicateWords()
{
Bag<String> words = this.getLowerCaseWords();

Bag<String> duplicateWords =
words.selectDuplicates();

Bag<String> expected =
Bags.mutable
.withOccurrences("in", 2)
.withOccurrences("sand", 2)
.withOccurrences("to", 2)
.withOccurrences("but", 2)
.withOccurrences("beaches", 2)
.withOccurrences("so", 2)
.withOccurrences("the", 10)
.withOccurrences("like", 2)
.withOccurrences("and", 3)
.withOccurrences("of", 5)
.withOccurrences("them", 3)
.withOccurrences("off", 2)
.withOccurrences("they're", 2)
.withOccurrences("our", 4)
.withOccurrences("we", 4);
Assertions.assertEquals(expected, duplicateWords);
}

Find unique words

The following code will find the words that are unique. We compare the result of calling selectUnique() to an expected Set<String>. The method selectUnique() returns a RichIterable when called on a Bag.

@Test
public void uniqueWords()
{
Bag<String> words = this.getLowerCaseWords();

RichIterable<String> uniqueWords =
words.selectUnique();

Set<String> expected =
Set.of("nobody", "they", "individual", "shake",
"by", "pawns", "sent", "were", "hide",
"would", "shirts", "on", "something", "dirt",
"thoughts", "sifted", "behind", "carelessness",
"gone", "much", "many", "washed", "children's",
"brush", "ask", "towels", "this", "ever",
"simple", "one", "about", "kings", "beauty",
"looking", "hand", "someone's", "can", "tide",
"glass", "for", "left", "treated", "mind",
"question", "tossed", "just", "with", "ourselves",
"society", "a", "boxes", "don't", "back",
"always", "us", "still", "seen", "seem", "should",
"playing", "know", "reflecting", "up", "cares",
"crystals", "never", "felt", "grains", "grain",
"miss", "yet");

Assertions.assertEquals(expected, uniqueWords);
}

Find the top three words

One of my favorite methods on Bag is topOccurrences(). This method does some neat things. We pass in an int parameter to specify the number of top occurrences, and then we get back a List of those occurrences as pairs, with the item and the total number of occurrences.

@Test
public void topThreeWords()
{
Bag<String> words = this.getLowerCaseWords();

ListIterable<ObjectIntPair<String>> topThreeWords =
words.topOccurrences(3);

List<ObjectIntPair<String>> expected = List.of(
PrimitiveTuples.pair("the", 10),
PrimitiveTuples.pair("of", 5),
PrimitiveTuples.pair("we", 4),
PrimitiveTuples.pair("our", 4)
);
Assertions.assertEquals(expected, topThreeWords);
}

Now what should immediately jump out of the code is that we said we wanted to top three words, and we actually got four. This is part of the specification of topOccurrences(). In the event of ties, more results may be returned. It is up to the developer calling the method to determine how to handle the event of ties in the data. Here we can see that “we” and “our” both occur four times in the poem.

Final Thoughts

I hope you enjoyed reading these code examples, and the poem I used in the examples as well. Parsing text and counting words using a Bag type is a simple fun example that should be easy to read and follow. Analyzing the results in a Bag can also be fun as the Bag type gives us useful methods to answer specific questions about the “counts” it maintains.

Java Text Blocks are a somewhat recent addition to Java that makes coding examples like this more fun and easier for humans to parse.

Thanks for reading!

I am the creator of and committer for the Eclipse Collections OSS project, which is managed at the Eclipse Foundation. Eclipse Collections is open for contributions.

--

--

Donald Raab
Donald Raab

Written by Donald Raab

Java Champion. Creator of the Eclipse Collections OSS Java library (https://github.com/eclipse/eclipse-collections). Inspired by Smalltalk. Opinions are my own.