Wednesday, March 4, 2020

Tech Book Face Off: Getting Clojure Vs. Learn Functional Programming With Elixir

Ever since I read Seven Languages in Seven Weeks and Seven More Languages in Seven Weeks, I've been wanting to dig into some of the languages covered by those books a bit more, and so I've selected a couple of books on two interesting functional languages: Clojure and Elixir. For Clojure I narrowed the options down to Getting Clojure by Russ Olsen, and for Elixir I went with Learn Functional Programming with Elixir by Ulisses Almeida. You may notice that, like the Seven in Seven books, both of these books are from The Pragmatic Programmers. They seem to pretty consistently publish solid, engaging programming books, and I was hoping to have more good luck with these two books. We'll see how they turned out.

Getting Clojure front coverVS.Learn Functional Programming With Elixir front cover

Getting Clojure

I remember thoroughly enjoying Russ Olsen's Eloquent Ruby years ago, so my expectations were already set for this book. Olsen did not disappoint. While Getting Clojure is an introductory programming language book instead of a guide on the idioms and best practices of the language, like Eloquent Ruby was, he brings the same clear, concise writing, and nails the right balance between covering the minutia and sketching an overall picture of Clojure without boring the reader to tears.

Programming books that aim to teach a language from front to back can easily fall into the trap of spending too much time on all of the gory details about the language's arithmetic and logic systems or every possible control structure. Maybe it's because Clojure is a simple and straightforward language that doesn't have the complications that other languages have in these areas, but this book was a very easy read through these normally tedious parts. Olsen assumes the reader is already a programmer with a couple languages under their belt, so he lays out the mundane facts in a succinct, orderly manner and moves on to the more interesting bits.

Chapters are short and evenly spaced, each focusing on one small part of Clojure, starting off with the basics of arithmetic, variables, data types, logic, functions, and namespaces. Each chapter has sections at the end for discussing how to stay out of trouble when using those language features and what those features look like in actual Clojure programs. After the basics he covers the more intermediate topics of sequences, destructuring, records, tests, and specs before finishing things up with inter-operating with Java, working with threads, promises, futures, and state, and exploring the power of macros. It's a logical order that flows nicely, with later chapters building on earlier material through a gentle learning curve. I never felt stuck or frustrated, and I could read through a few chapters in a sitting at a rapid pace. That's testament to excellent technical writing skills that allow an experienced reader to go through the book at speed.

One fascinating thing about this book, and I imagine every Clojure book, is how little time is spent explaining syntax. Clojure is a Lisp-style language, so syntax is kept to a minimum. What do I mean by that? Well, the basic syntax of Clojure is a function call, followed by its arguments, both wrapped in parentheses like so:

(println "Hello, World!")

Vectors are denoted with [] and maps follow the form of {:key1 value1 :key2 value2}. Nearly all of the code looks like this, just with more complicated nesting of functions. After learning the standard library functions, you know and understand about 90% of the language! The more advanced language features like promises and macros add some more syntactical sugar, but really, compared to C-style languages, Clojure's syntax is incredibly lightweight. Some programmers may hate all of the parentheses, and the prefix arithmetic notation takes some getting used to, but learning a language that's so consistent in its structure is enlightening.

Not only does Clojure have the elegance of a Lisp, but it also runs on the JVM so we have access to all of the Java libraries that have been built up over the last few decades. That may not always seem like a benefit, considering how convoluted some Java libraries are, but Clojure has its own great features that should take precedence over the uglier parts of Java while still being able to leverage all of the time-saving work that's been done already.

Plus, Clojure has made significant advances in modern concurrent programming, both through its inherent nature as a functional language with immutable data structures, and because of safe concurrent programming structures like promises and futures. As Olsen says about threads, "One of the things that makes programming such a challenge is that many of our sharpest tools are also our most dangerous weapons." If concurrency is anything, it's hard, but Clojure makes this increasingly important programming paradigm easier and safer, as long as you know how to use those sharp tools.

Olsen has done a great job of teaching the set of tools available in Clojure with this book, and beyond it being clear and well written, it was a fun read all the way through. I love learning new languages and the new programming tools that they reveal, especially when I can find a great field guide like this one to help me along the way. If you don't know Clojure and would like to learn, Getting Clojure is a highly recommended read.

Learn Functional Programming with Elixir

Like Clojure, I wanted to dig more deeply into Elixir after reading about it in Seven More Languages in Seven Weeks. This book showed some promise as a quick introduction to the language that would focus on the functional programming paradigm. I think the title is a bit of a misnomer, though, because it was more on the side of a quick introduction to Elixir, which just happens to be a functional language. Almeida did not go into too much detail about how to use the functional paradigm to greatest advantage, and instead stuck to the basics.

Spending time on the basics is fine, of course. It just wasn't what I was expecting. The book is split into seven chapters that cover a quick introduction of what Elixir looks like, variables and functions, pattern matching and control flow, recursion, higher-order functions (like each, map, and filter), an extended example text game, and impure functions. Notably missing from this list is anything having to do with concurrency and parallelism—Elixir's primary claim to fame, being that it runs on the Erlang VM. But this is a beginner's book, after all, and it keeps things pretty simple, although the pace is probably too fast and the explanations too short for someone who has never programmed before. This book is definitely meant for experienced programmers looking to get started with Elixir quickly.

In that respect, the book accomplishes its goal quite well. It presents all of the basic features of Elixir in a logical and succinct manner, covering all of the different syntax elements of the language without much ceremony. Elixir has its fair share of syntax, too, much more so than Clojure does. Whereas Clojure consists entirely of function calls, Elixir syntax is much more exotic:

max = fn
x1, x2 when x1 >= x2 -> x1
_, x2 -> x2
end
This is a simple function that returns the maximum of two numbers, but it shows some of the more extensive syntax of Elixir with pattern matching on the second and third lines, the when guard clause, the underscore used as a wildcard matcher, and the anonymous function declaration. When this function is called, if line 2 matches, including the guard clause such that x1 >= x2, then x1 is returned. Otherwise, line 3 will match automatically and x2 is returned. This is just a sampling of syntax, too. Things get even more involved with lists and maps and function arguments, all mixed in with pattern matching and pipes. This is a rich language, indeed.

The brief explanations of all of these language features tended to be a bit wanting. They were so clipped and simple that I was often left wondering if there wasn't much more to some of the features that I was missing. The writing style was abrupt and disjointed to the point of being robotic. Here is one example when discussing recursion:
Code must be expressive to be easier to maintain. Recursion with anonymous functions isn't straightforward, but it is possible. In Elixir, we can use the capturing feature to use named function references like anonymous functions:
Here's another example when describing the Enum module:
The Enum functions work like our homemade functions. The Enum module has many useful functions; it's easy to guess what they do from their names. Let's take a quick look:
This kind of writing just starts to grate on me because it has no natural flow to it. I would end up skimming over much of the explanations to try to pick out the relevant bits without feeling like I might be assimilated by the Borg.

Most of the code examples were forgettable as well. They did an adequate job of showing off the language features that they were meant to showcase, but they certainly didn't serve to inspire in any way. On the other hand, chapter 6 on the extended example of a text game was quite delightful. This chapter made up for most of those other faults, and made the book almost worthwhile.

In the example game, you code up a simple text-based dungeon crawler where you can pick a hero and move through a dungeon fighting monsters. It's an incredibly stripped down game, since it's developed in only about 35 pages, but it shows Elixir in a real application setting, using all of the language features that were introduced in the rest of the book. It was fun and illuminating, and I wish the rest of the book could have been done in the same way, explaining all of the Elixir syntax through one long code example.

Alas, it was not done that way, but even though the rest of the book was terse and didn't cover some of Elixir's more advanced features, it was still a decent read. It was short and to the point, making it useful for a programmer new to Elixir that needs to get going with the language right now. For anyone looking to learn Elixir more thoroughly, and maybe more enjoyably, you'll want to look somewhere else.


Of the two books, clearly Getting Clojure wins out over Learn Functional Programming With Elixir. Olsen showed once again how to write a programming book well, while the Elixir book was mechanical and insufficient. That's great if you're in the mood to learn Clojure, but what about Elixir? It's a fascinating language, but I'll have to look further to find a good book for learning the details.

No comments:

Post a Comment