Search This Blog

Tech Book Face Off: Seven Languages in Seven Weeks Vs. Seven More Languages in Seven Weeks

Yes, that's right. I learned fourteen programming languages in as many weeks. Actually, it was more like four weeks, but I just couldn't put these books down. I had wanted to work through them ever since I had read Seven Databases in Seven Weeks a few years ago and loved it. Now I finally made the time to read them, and had a blast the whole time. I shouldn't have waited so long to crack these books open. I started off with Seven Languages in Seven Weeks by Bruce Tate, and then quickly moved on to consuming his follow on book, Seven More Languages in Seven Weeks, co-authored with Ian Dees, Frederic Daoud, and Jack Moffitt. It's not as hard as it would seem to learn about so many languages in such a short amount of time, as long as you already have a few under your belt, because really the hardest programming language to learn is the second one. After you overcome the confusion of holding two different languages in your head, it becomes much easier to add another and another and another. The differences get slotted into your brain more readily, and the major hurdle becomes figuring out how to use the new paradigms and features that you run up against. Let's see how these books handled presenting all of these different languages and smoothing the shock of moving from one language to another in rapid succession.

Seven Languages in Seven Weeks front coverVS.Seven More Languages in Seven Weeks front cover

Seven Languages in Seven Weeks

With such an ambitious goal crammed into 300 pages, Bruce Tate certainly had to take some shortcuts with this book. Those cuts included any installation instructions beyond a link and a version number, detailed descriptions of the literals, operators, and control structures of each language, and extended tours of the standard libraries. There's just no time for that crap, and it's expected that if you're reading a book like this, you've been around the block a few times and can either figure out how to write basic lines of code in any language on your own or you know how to google it. There are more important things to cover for these languages.

Each of the seven languages gets its own chapter, split into three days. The first day introduces the basics of a language with some quick examples and an interview with the language's creator. The second day starts covering the unique aspects of the language and gets further into the programming model. The third day usually gets into the concurrency aspects of the language, if it has special constructs for concurrency, or some other special aspect of the language, like metaprogramming in Ruby or monads in Haskell. At the end of each day Tate gives some good exercises to help solidify the ideas presented for that day and lead into the next day.

The discussions were great—concise and to the point while also being clear and extremely helpful for understanding the difficult parts of each language. To make the material even better, all throughout the book the languages are compared with popular movies. It was entertaining to see Tate go from Ferris Bueller's Day Off to The Princess Bride to The Matrix without missing a beat. I never knew which movie reference would pop up next, and it made me keep plowing through for more. It was a wild ride. So what were the seven languages covered?

First off was a language I already knew pretty well. Ruby is a beautiful language that achieves its goal of making programmers happy. It's probably my favorite language of all the ones I (now) know. It's a straight-up object-oriented language where everything is an object, including literals and operators. Tate covers duck typing, code blocks, mixins, the almightly Enumerable module, and of course metaprogramming. In three short days you can really get a sense of what makes Ruby a great language for programmers.

Io is a prototypical language, meaning everything is an object, but there are no classes. Objects are derived from other objects and then changed by adding parameters and functions to slots in the object. It's quite a small language without many extra features or syntax, but it is definitely a flexible language. The programmer has complete freedom to change how objects behave by changing their base functions. It took me a little while to wrap my head around how to program in this language, but it was very satisfying to figure it out.

This language is probably the weirdest one in the set. Prolog is a pattern-matching (a.k.a. logic programming) language that excels at certain types of problems like scheduling and natural-language processing. Instead of a program being made up of expressions and executing statements in a sequential order, Prolog programs are made up of facts and rules, and the runtime environment solves for the rules given the facts and a question posed to it by trying different combinations of values for the free variables. It's a fascinating language. Mind-bending, but fascinating.

Scala is a hybrid language that is equal parts object-oriented and functional. It's the modern day equivalent of C++ for hybrid procedural and object-oriented programming, and it runs on the JVM so it has access to the entire Java edifice. Bridging these two programming paradigms makes it an important language to watch, but I could tell Tate thought it was rather boring. This chapter was the dullest of the bunch, and programming in Scala seemed fairly straightforward using either paradigm, compared to many of the other languages.

Erlang is built on top of Prolog, so it retains much of the same weirdness of Prolog's pattern-matching logic programming paradigm, but softens it somewhat. What makes Erlang unique is its incredible robustness for highly-concurrent programs. Instead of threads, Erlang spawns lightweight processes for each task that needs to run in parallel, and those processes can be monitored and quickly restarted if they fail. It's a compelling concurrency model. You just have to get over the Prolog roots.

Here it is—the one Lisp language of the set. Clojure runs on top of the JVM, like Scala, but it takes the path of a functional language. Personally, I love programming in Lisp. It has a certain elegance and expressiveness that other languages can't duplicate, and it's great to see a version of it have a chance at wider adoption in Clojure. It even eases the code syntax a bit by removing some of the parentheses. This chapter was especially enjoyable to work through.

Tate saved the most challenging language for last. Haskell builds on many of the features of the other languages with pattern-matching, lazy evaluation, and list comprehensions. It is strongly-typed like Scala and uses type inference to take much of the burden of specifying types off of the programmer. Haskell's type system is truly legendary, and this chapter only scratches the surface of it. Haskell's also a purely functional language, so monads are needed to handle I/O and mutable state. I feel like I barely caught a glimpse of this language, but this chapter has motivated me to learn more.

I had such a blast going through this book and learning all of these languages, many of which I've been meaning to take a look at for some time. This book allowed me to do that efficiently, and now I know what I want to explore in more depth. While I wouldn't say I learned any of these languages in any detail, I was able to see the strengths and big ideas surrounding each of them, and I have a better sense of which languages are well suited for different kinds of problems. Sometimes that's half the battle of solving a problem. This book is a phenomenal resource for quick tours of different languages and programming paradigms. I can't recommend it highly enough.

Seven More Languages in Seven Weeks

Whereas in the first book I had at least known of all of the languages and was already fluent in one of them, nearly all of the languages in this book I had never heard of before, save one: Elixir. That ended up not mattering much, since almost every language was related to one that I already knew in some way. That meant I could slot the various programming models into my brain based on how they compared and contrasted with other languages. Not knowing of them before hand didn't make any difference in being able to learn about them during the course of the book.

I certainly learned plenty of new things as I went through the book, but by now you may be wondering, why am I subjecting myself to this onslaught of languages between these two books? As Bruce Tate explained in the introduction:
Each new language exposes you to a vocabulary, but not one of words. This new vocabulary is composed of the ideas that you use to shape your world. Though the precise syntax will almost certainly not commute from your sandbox into your production solutions, you'll see that many of the idioms do.
Different languages excel at different things. They have different programming models, and different things that they make easy or hard to do. They have different ways of solving problems. Learning about those different ways of doing things makes every program you write better because you can bring more resources to bear on the problem, even if you don't get to use the language that would be best suited to it. With that perspective in mind, let's see which languages this cadre of authors chose to explore.

Lua is a scripting language in the truest sense of the word. It's commonly used as the scripting language for video games and big scriptable applications. It runs almost anywhere, and is commonly used in embedded systems as a higher level language than the old stalwart embedded workhorse, C. It also integrates easily with C, and they showed how to do exactly that on day 3 of this chapter. The overarching abstraction in Lua is the table. Everything in the language is a table, and data and functions are added into an object's table to enable state and behavior. Tables even have metatables that allow the programmer to write their own programming models and override basic language behavior. It's an amazingly flexible paradigm for a language.

This language was the weird one of the bunch for this book. Factor is a stack based language as well as a functional language. While most functional languages use prefix notation (+ 1 1), and most other languages use infix notatation (1 + 1), because of the stack, Factor uses post-fix notation (1 1 +). Prefix notation is hard enough to switch to, but post-fix notation will melt your brain. It took awhile to get the hang of mentally parsing the code, and I don't feel like I truly grasped the advantages of this stack language. It was a fascinating exercise trying to learn it, though, and I'm glad it was included.

Elm was created specifically to bring some sanity to client-side JavaScript programming. It's a strongly-typed functional language that compiles to JavaScript, and is intended to be used for user interface development. The killer feature that makes Elm so interesting in this regard is signals. Instead of using callbacks to write asynchronous UI code in the browser, Elm programmers can configure signals that are generated by various interface elements and can be received by other code in the program to initiation relevant processing. It's a welcome escape from callback hell, and a really clean programming model for the browser. If only the language would hold still for a little while. It had changed significantly between the writing of the book and now, so it took some time to get certain parts of the code examples working.

What I knew of Elixir already was that, like Ruby, it has a ton of syntax sugar to make code compact and beautiful. That's true, but it's not all. Elixir is built on the Erlang VM, so it comes with the same robustness and safety for concurrent programming that Erlang has refined for decades, as well as access to the Erlang libraries. Elixir is also a functional language, and adds other fresh programming features like the pipe |> operator for chaining functions together and for comprehensions, which are kind of like list comprehensions on steroids. To top it all off, Elixir has a powerful Lisp-like macro system to enable metaprogramming.

Julia is meant to be a scientific programming language in the same vein as MATLAB, R, and Python (well, Python is not specifically for scientific programming, but it's heavily utilized for that purpose). Julia is a dynamic language, but it's compiled so it doesn't suffer from the same performance slowdowns as the other interpreted languages. The goal is to get scientific computing performance from an easy to use language, and Julia makes some interesting trade-offs there. It also has plenty of syntax sugar for doing linear algebra and DSP calculations. I'll be curious to see if it makes any inroads into the machine learning space.

This language is the logic programming language of the group, but it doesn't have the weird syntax of Prolog. It's built on top of Clojure, so it has the weird syntax of Lisp instead. The neat idea with miniKanren is that because it's layered on top of Clojure, it's a logic-and-functional programming language, and that combination greatly increases the problem space for which it's well suited. Clojure can be used for program I/O and pre- and post-processing, and miniKanren can be used precisely where it shines with solving logical problems cleanly and efficiently. Another fun fact is that miniKanren is an implementation of the logic programming language developed in The Reasoned Schemer, which is another book I've been meaning to read.

The final language is another pure functional language with a strong type system, like Haskell in the previous book. They always save the most complicated language for last, don't they? Idris is written in Haskell, and it takes Haskell's type system to the next level with dependent types. This type system enables new kinds of type-checking sorcery by specifying that a vector type must be a certain length, for example, or that the output matrix must have the same dimensions as the input matrix. Types can even be dependent on operations of other types, so we're really programming in types here. I'm not sure, but Idris' type system might be Turing complete in and of itself.

The format of these seven chapters was fairly similar to the last book, but with four different authors, the tone was a bit different. The analogies with movies were still there, although I would say they weren't quite as entertaining. Instead, on each third day the authors showed the reader how to implement something relatively significant in the chosen language, and that exercise was quite satisfying. From a mini-game with bouncing heads in Elm to a rudimentary JPEG compression algorithm in Julia, the programming tasks they came up with were good and showed off the strengths of each language. It's another highly recommended book on multiple languages that was extremely well done.

So did I learn fourteen languages in four weeks? No, of course not, but that's not the point. All four authors from the second book said it best near the end of the book:
Some will try to tell you that this journey is worthless, that you can't truly learn a language in seven days any more than you can learn Italian by eating at the Olive Garden once a week. If you've worked through these exercises, you know different. Traveling for the sake of traveling is not worthless. True, on your brief trip you've not yet accumulated the fluency of a permanent resident, but you have been there.
I've learned a ton of new things from these two books and fourteen languages. They were all so different that the number of ideas covered was incredible. I had no idea that the world of programming languages was so rich and varied, and I've come away from this experience wanting to learn even more. I'm certainly going to explore Clojure, Prolog (or miniKanren), Elixir, and Elm more deeply, and I may even delve into Io and Haskell if I can find the time. These books have shown me much more of the map, and that it is filled with fascinating destinations. Now I know better where I want to go.

No comments:

Post a Comment