In 2017 I started to learn more about the universe of Functional Programming. This paradigm was gaining traction and most object-oriented programming languages were adding more and more features inspired by this paradigm, including the language that I used the most: Java.
After the JDK 8 release in March 2014, it became common to hear Java developers using terms like: functional programming, streams, optional, map, flat map, etc. But many people around me still ignored these new features and, I confess, it took me a while to adopt them. The ideas sounded very interesting, but putting them into practice turned out to be more difficult than I expected.
After much trial and error, I decided to dig deeper into the concepts. The book Functional Thinking helped me take my first steps in the right direction.
In parallel I decided to learn a functional-first programming language instead of trying to partially apply the functional paradigm in an object-oriented language. After doing a lot of research, I chose to learn Elm. The fact that it is a pure and immutable functional language caught my attention. Also, it is focused on webapps development and, until then, I hadn't found any solution for developing web pages that I liked.
After going through the whole Introductory Guide to the Elm Language and reading the Elm in Action book, I already felt quite comfortable developing webapps in this paradigm. I liked Elm so much that I started a project to teach programming to beginners using this language and made the first classes available on the website elm.dev.br (in Brazilian Portuguese).
But there was a serious problem that I still had to face: Elm is a language designed for webapps development and works very well for that, but I was looking for a general purpose solution, that could also be used in backends development. So I started hunting for another language again.
Elm is a statically typed language inspired by Haskell. The natural step would be to use Elm on the frontend and Haskell on the backend. And that's what I tried to do. I read with some difficulty the Learn You a Haskell for Great Good! book (available for free here) and learned a lot of cool stuff. But creating a complete backend using Haskell proved to be more than I could chew. So I decided to look for alternatives...
During this whole process the word Lisp kept popping into my head! From time to time I would come across a video of someone influential in the community talking about it (like this video or this twit by John Carmack, founder of id Software). It felt mystical. And the fact that Nubank adopted Clojure brought a very real and pragmatic case study of the use of a Lisp dialect here in Brazil.
Until then I was postponing studying it because I was prioritizing statically typed languages and the most famous dialects of Lisp are dynamic languages. But in early 2021 I finally decided to give it a chance. I chose the language Clojure and started reading the Getting Clojure book. Unlike my Haskell studies, I managed to read this book in just a few days! At the same time, I started taking Clojure classes at Alura (a popular online programming school in Brazil), which helped me to see how to program in this language in hands-on. It was a good combination: in the book I learned the concepts of the language more deeply and in the course I reviewed these concepts and learned the more practical parts.
Clojure's key features
Lisp is not a programming language, but a family of languages with many dialects. The most famous dialects include Common Lisp, Clojure, Scheme and Racket. So after deciding that I was going to learn Lisp, I had to choose one of its dialects.
Clojure stood out to me for two reasons:
- it uses the Java Virtual Machine, enabling interoperability with Java applications (which, as I said at the beginning of the article, is the language I usually use in the backend).
- it predominantly uses the functional paradigm. Some Lisp dialects (like Common Lisp) are multiparadigm, but as my intention was to go deeper into the universe of functional programming, it made sense to adopt a dialect that was functional first.
The experience of programming in Clojure was quite liberating. Practice TDD together with REPL Driven Development (technique quite widespread inside the Clojure community) makes the feedback loop very fast. The fact that Clojure is a dynamic language also contributes to that.
Another characteristic of Clojure is that it is an impure language, that is, we can have side effects at any time. The main advantage of this is that it makes the language easier to learn (although it brings with it a host of other problems that don't happen in purer languages like Elm or Haskell).
But although it is an impure language, it encourages a series of good practices that significantly reduces the potential problems of this approach.
Getting started with Clojure
Clojure might be intimidating at first, but after a few hours you get used to it's syntax and it's actually quite easy to learn. That's why I also chose this language to share with other developers the basic fundamentals of functional programming.
If books are your thing, I recommend starting with Getting Clojure, which as I said earlier, is a great way to understand the basic principles behind Clojure. But if you are looking for a free option, you may start with the online version of the Clojure for Brave and True book. Another option more focused on the foundations of the paradigm and that addresses languages other than Clojure is the book Functional Thinking, by Neal Ford.
I created a 10 hours course on Introduction to Functional Programming with Clojure with optional payment (yes, you can enroll for free if you want to!). But right now it's only available in my native language: Brazilian Portuguese. 😉
And you, what is your favorite paradigm? Have you tried programming using the functional paradigm? What were your main difficulties? Share your experiences in the comments!
Did you like this text? Checkout my other articles at: https://segunda.tech/tags/english and follow me on twitter.
Top comments (7)
Check out Roc which aspires to be Elm for the backend: roc-lang.org/
Re:
Hello Magne. Thanks for your comment.
Yes, I'm following it through Richard Feldman's talks and the Unscripted Podcast.
A very interesting project indeed!
I moved to developing Elixir and Erlang after 16 years of Ruby and Ruby on Rails development. I haven't looked back. I still love Ruby and I still work daily in rails apps but I, personally, like functional paradigm better.
As of 2023 no general purpose functional language is complete and feature rich as Scala. Closure maybe a good option to have fun while programming or developing recursive solutions for functional requirements, but it's not an industry level language. With Scala you have a language for any purpose including industrial systems. Addressing non functional requirements is not easy with Closure, and industry need quality first languages.
Soundness properties of Scala has no competitor yet. ScalaJS is much more flexible than Elm, dedicated to front end development. Being the first and only object-functional language it's easy to develop in OOP as well as FP, to ease migration for Java developers. Java has borrowed many features from Scala, with no success to catch Java developers attention, because Java syntax is a burdon to implement patterns based on newly introduced features. Type inference makes developing in Scala feel like dynamic languages while being completely type checked, so JS and Python are already deprecated. As soon as Scala native becomes mature enough, Rust will be beaten as well.
Scala is definitely the language of future, with no doubt.
Good thing that Clojure is an industry level language then.
Kotlin seems to be another very popular alternative for the JVM.
For the .NET platform then F# would give any language a run for its money, when it comes to soundness of the type system (being based on OCaml), or when it comes to the OOP and FP multi-paradigmaticity.
All the languages you mentioned lack consistent design decisions, because new features added later and are like patches to the original language features. The features you ascribe to those languages never been part of their original design.
After all why should I learn 5 languages when all their features are combined in a single language called Scala!??
Besides, Scala solved many problems to be able to put all these features together, but the languages you mentioned just have some of Scala features and none of them can evolve to embrace them all because early design decisions affect later ones. Such evolving translates to solving several side problems to be addressed by language designers, and it cannot be done as easy as it's said.
The same features come from 2 or 3 languages cannot have language level interaction, it means there could be synergy between e.g. soundness and abstract syntax tree representation of programs in the most principled typed meta programming out there in the world (Scala 3) which cannot be implemented neither in one of the languages you mentioned nor in their interactions.
So I guess it's just a cultural resistance against Scala by old school language lovers.
As the first law of software architecture states: Everything in software architecture is a trade-off.