“Why is this code so messy? Why is this problem sooo difficult to express? What a hell is going on in this code?”
Questions like that pushed me many times on a quest for the Holy Grail of programming languages. I have not found a Grail, but like with every journey, I got wiser and more experienced.
Programmers have been looking for the best way to express themselves to a computer for a long time. Among all the languages ever created, only a handful grew to become the widespread industry standards.
Like me, you are probably using battle tested, popular technology and try to make it work for you in the best possible way. But we all know that things are not perfect — they have their flaws that work on our nerves and patience.
Here is a shortlist of the languages that I tried, and which brought me some good in my everyday work. While not being an expert or even regular user of most of them, I had a lot of fun experimenting with these languages, and I like to think they just made me a better programmer in general.
ML languages (F# / OCaml)
For the first entry, I would like to present you with the languages of the ML family. It wasn’t my first dive into the Functional Programming (FP) world. It was however one that brought me a real practical understanding of how this actually should work.
Although both languages do support multiple paradigms, they are best suited for functional programming. They are not as strict and pure as Haskell, so you can dip your toes in the Functional Programming style without so much initial struggle and frustration.
I really love how easy it is to control the flow with matching and destruction. F# great at visualizing the flow of the function at glance. It’s a trait that I strive to incorporate in my code regardless of the language.
Thanks to ML languages, I got better at the composition and design of my types. Even though F# will try to guess your types from the code that you write at its core, it is a strongly typed language.
F# is great for learning functional style operations on the sequences. This is a common trait for any FP first language. Folds, Maps Zips, etc. are equivalent to the hammer in the FP programmer toolbox. Strong emphasis on this element, supported by the syntax that makes it easy to use, will help you train your brain to see the problems that can be abstracted to sequence operations.
Learning F# is an excellent first step into the functional programming world if you have experience with OOP (Object Oriented Programming). If you get stuck, you can always get back to your everyday objects and classes. F# blends them with other code without much of the fuss.
F# interoperability with .NET is also a big help if you have experience with C#. You can still use your trusty .NET tools and nuget packages.
I can only recommend that you should try it. It’s good fun without a very steep learning curve.
But if you are not afraid of the steep learning curve, then you can jump straight to:
Now, Haskell was (and still is) a challenge that I like to go back to now and then. Even though I never finished any big size project, I always enjoy the mental challenge of working with it.
Haskell programming was a brutal experience at the beginning… and to be honest, it still is. Haskell is not a fluffy user-friendly ML language. This language will force you to program FP, and to program correctly.
You have to design your types correctly. You have to plan your functions precisely. And there is no cheating on implementation, if you said that this function will do something, you have to deliver on your promise. No half implementations, no missed cases, or ‘elses.’
But most importantly, no hidden side effects. If you said that your function will get a string and get the string back, then the compiler will force you to deliver on your promises. No printing debug information, no reading user input. You said that you will get a string and give the string back ONLY, didn’t you?
Working with this language really tunes your brain to be mindful about what you promised declaring the function (or method).
Even though this strictness will not always translate well to languages like C#, it will make you more aware, and will push you to carefully declare functions so another user will not have unpleasant surprises. And it will save you some swearing when you come back to your own code after a year or two.
I know that my brain instantly sounds the alarm when I modify any arguments that are passed to the method. Did I need that? Did I warn a potential user that the function will mess with his/her data?
Haskell was a bizarre language when I started learning it. I knew already that Haskell programmers sit at the top floor of the programming ivory tower. What I also discovered is that apparently strange creatures are hovering above the top of the tower itself (joke credits goes to ScottW).
And these guys program in:
LISP family: Common LISP, Clojure, Scheme
This is a truly alien one to anyone who, like me, comes from a C family. The first puzzled look at the code, the first crossed eye gaze caused by a crowd of braces hugging the statements. Ah, memories!
My first step into the LISP world was through the Clojure. I was just browsing in the bookshop, when a book on Clojure caught my eye (for the love of me, I don’t remember which book it was). I took it home, and the adventure began. Or, to be exact, days of solving puzzle after puzzle and of trying to understand how the hell to use this thing. I gave up after a few weeks, then came back to it after a year. And gave up again. Then I found Common LISP, and let it go again, but this time with the added value of discovering that EMACS is what I want from my text editor (and maybe operating system).
I don’t remember at what point of this cycle something clicked. The braces blended into the background, and what was left was just a clarity. If there is one thing that you will find in LISP, it is elegance. I would not in the world say that I can write top of the line code in LISP, but reading a code of experienced programmers is an experience of awe and envy. I hope I will have the skill one day to write programs that explain themselves so beautifully.
If I can give one testimony to the awesomeness of these languages, it is that more often than not, I can understand the intent of the program even if I don’t have enough knowledge to write it myself.
All this is thanks to the simple yet flexible design. On top of that, there is a Macrosystem that is second to none that I know of. This gives you the power to write your programs around the problems that you solve, with supporting syntax construction.
Another significant feature is interactive experimental programming with a REPL’s. Working on the living code encourages experimentation and allows you to check many ideas before you commit to one design for your code.
Even though I don’t use LISP in my job, it is still a great tool to have, and I found the truth in the often-quoted sentence “Learning LISP will make you a better programmer.” I don’t know if I am a better programmer thanks to LISP, but it definitely has broadened my horizons.
I first found out about Rust when I was dealing with a C++ pet project. I don’t hate or despise C++, but anyone who uses it knows that it can sometimes be a bit annoying.
The complexity and freedom that C++ provides is amazing, but it can also be overwhelming, to the point of losing hope…
If you have never written a medium/big size project in it, then let me just tell you that it can get messy pretty fast.
The driving idea behind this behemoth of a language is that for no reason developers should be prevented from shooting his or her own foot… or 20 feet that just happen to be there now and you are not sure how they got here. Also, your original foot is somewhere, but you are not sure where anymore.
Anyway. Rust deals with the problem with the strictness of the RAII paradigm and being opinionated AF. In a way similar to Haskell’s, the compiler stays on top of things and ensures that you are structuring your program correctly.
The main goal being: if it compiles, it will work correctly.
Writing in Rust is like working with an angry trainer who will correct you on the slightest slip-up.
It’s good practice, especially if you struggle with getting your memory management just right.
Rust seems to get significant improvements every time I take a look at it. Even if it won’t replace C++ for mid-level general-purpose language, still it is good to have a good contender in place.
This one was recommended to me by my friend in the middle of a bar argument about Object Oriented and Functional paradigm. Adequately fueled by the beer, I took the stand of a functional programming neophyte who thought that this new paradigm was going to solve all of my problem’s, if not the world’s.
I got countered with a simple argument:
Try Smalltalk and see if Object-Oriented programming is really useless.
So I tried and was humbled. It turns out that I had no idea how to do OO. Smalltalk is specific. Most of the implementations: Pharo, Squeak, etc. will give you a full IDE, which is almost like a small operating system built just for development.
It gives you all the tools to do the job, but most importantly, it strongly suggests the workflow that shows you how to develop in what I would call, the Smalltalk way.
So you do comment, you do write your tests. You take care of naming and cataloging your objects and functions into proper Objects, Protocols, and Packages.
Call me crazy, but I feel like Pharo is almost proud of me when I do things the correct way.
Turns out the right way pays big time.
The language itself is very simple, and you can easily learn the syntax in less than 15 minutes. No tricks, no syntax sugar. It gives you just enough tools to get the job done, so you do it. Your mind does not wander trying to find which language tools you should use — there is no choice. I feel like it allows my brain to focus all its power on the work at hand. It works for me, maybe it will work for you.
There are languages that I skipped in this article. Some of them are so widespread that you probably have seen them in another form like Python/Java/C++/C# etc…
Some, like Ruby, Scala, Perl, I just haven’t tried yet. I hope I will get to know those better in the future.
Whether you had a similar learning experience or a completely different one, I would love to hear from you in the comments.