Earlier this year, I had a conversation with Andy Hunt and Dave Thomas (joint authors of The Pragmatic Programmer and original signatories of the Agile Manifesto). They recommended (and have suggested in the past) the practice of learning at least one new programming language a year.
The reasoning behind this practice has very little to do with marketing oneself or even using the language. In reality, the most significant benefit of learning a new programming language is the stretching of the mind and the creation of new neural pathways that allow you to look at problems in new and unique ways.
I've compiled this list of languages primarily because they are languages I'm interested in spending more time learning, but also because they exemplify specific language characteristics and programming ideologies very well.
So without further ado, this is a list of languages you should learn to stretch your brain:
1. Ruby
Ruby is built for programmer happiness. That can mean different things to different people, but it's the first programming language that I've come to love.
The interesting thing about Ruby is that it's designed to embrace Object-Oriented Programming.
OOP was created by Dr. Alan Kay, who once said: "Object-oriented programming to me means only messaging, encapsulating and hiding state, and extreme late-binding of all things." Ruby is good at this stuff.
Due to the nature of Ruby's message-sending-obsessiveness, it's an incredible environment to learn true OOP. I recommend Sandi Metz's wonderful Practical Object-Oriented Design in Ruby as an introduction to Ruby's strengths when it comes to designing objects and message sending.
Another mind-stretching feature of Ruby is arguably more divisive than OOP. Ruby embraces metaprogramming, which can be loosely defined as code that can reason about and generate other code.
Being able to manipulate programs via metaprogramming, while sometimes frustrating, can require an extreme paradigm shift in your mental model of the relationship between programmer and programming language.
# FizzBuzz in Ruby
# https://github.com/zenware/FizzBuzz/blob/master/ruby.rb
def fizz_buzz(num)
result = ''
result += 'Fizz' if (num % 3).zero?
result += 'Buzz' if (num % 5).zero?
puts result.empty? ? num : result
end
(1..100).each { |x| fizz_buzz x }
Resources:
2. Elixir
While Elixir might look a little bit like Ruby, it's very different. It's a functional programming language.
Elixir is a language that embraces an idea called the Actor Model, devised by Dr. Carl Hewitt. In the Actor Model, everything is an actor.
("Everything is an actor" sounds a lot like "everything is an object," but I'll leave such comparisons to academics)
Learning to think about actors is a challenging mental exercise that will lead to seeing problems in a new light.
Another mind-bending feature of Elixir is its relationship with Erlang. Elixir runs on the Erlang VM (BEAM), meaning that at some point most Elixir developers have to develop some comfort with Erlang.
I could easily run off on a tangent here, but the most interesting thing about Erlang (in my opinion) is its mind-boggling prowess when it comes to concurrency. Writing Elixir means learning to think concurrently, a skill that can be applied in a multitude of programming environments.
Finally, Elixir is a beautiful exemplar of a concept called pattern matching. Pattern matching is a very powerful functional language feature that enables you to interact with data in a very concise and safe way. Pattern matching is not exclusive to Elixir, so a solid understanding of pattern matching in your Elixir code will translate to other languages and problems easily.
# FizzBuzz in Elixir
# https://github.com/zenware/FizzBuzz/blob/master/elixir.exs
fizzbuzz = fn n ->
cond do
rem(n, 15)== 0 -> "FizzBuzz"
rem(n, 3) == 0 -> "Fizz"
rem(n, 5) == 0 -> "Buzz"
true -> to_string n
end
end
Enum.each 1..100, &IO.puts(fizzbuzz.(&1))
Resources:
3. Rust
Rust is an up-and-coming systems language. That means it's particularly suitable for writing software when performance matters.
Rust is a fast, compiled language that brings some new ideas to the table. It is expressly intended to solve a number of the memory safety issues that arise when writing C++, which is frequently used to solve similar systems programming problems.
In Rust, you can learn about writing low-level code that interacts directly with hardware, you can learn about concurrency, you can learn about a couple of different paradigms, and you can learn it all with relative safety.
One of the most attractive things about the Rust language is that it opens a problem space customarily associated with languages infamous for their pitfalls and arcane idiosyncracies to mere mortals.
Learning Rust forces you to learn about the machine running your code without forcing you to worry about solved problems.
One other brain enlarging feature in Rust is called macros. Macros are a form of metaprogramming that enables developers to write less code and be a little less specific when it's convenient. Not without caveats, macros are challenging to reason about and therefore can help you to develop a different perspective on the metaprogramming you've seen in languages like Ruby.
// FizzBuzz in Rust
// https://github.com/zenware/FizzBuzz/blob/master/rust.rs
fn fizzbuzz(i: u8) {
if i % 15 == 0 {
println!("FizzBuzz");
} else if i % 3 == 0 {
println!("Fizz");
} else if i % 5 == 0 {
println!("Buzz");
} else {
println!("{}", i.to_string());
}
}
fn main() {
for i in 1..101 {
fizzbuzz(i);
}
}
Resources:
4. TypeScript
You could make the argument that TypeScript isn't a language; it's a "superset" of a language. That's fine. It's still on my list.
For those who are unfamiliar (which would be hard considering its popularity), TypeScript is a language that compiles directly to JavaScript. It adds some additional features to the JavaScript language, but it still feels like JavaScript.
The brain stretching in TypeScript comes from the incremental approach in which it can be adopted and its focus on static typing. If like me, you come from a web background with languages like Python, Ruby, or PHP, static typing is generally a foreign concept. However, TypeScript is a friendly way to introduce yourself to this handy language feature.
Learning TypeScript will deepen your understanding of the JavaScript ecosystem, give you a strong vision of the future of JavaScript, and introduce you the benefits of static typing.
// FizzBuzz in TypeScript
// https://github.com/zenware/FizzBuzz/blob/master/typescript.ts
function fizzbuzz(num: number): string | number {
if (num % 15 === 0) return 'FizzBuzz';
if (num % 5 === 0) return 'Buzz';
if (num % 3 === 0) return 'Fizz';
return num;
}
for (let i: number = 1; i <= 100; i++) console.log(fizzbuzz(i));
Resources:
5. Haskell
Haskell is the most esoteric language on this list. It has lofty goals and ideals that make it excellent for challenging your brain.
Haskell is described as "purely functional" meaning that state is entirely immutable in this programming language. Learning to work with totally immutable state forces you to develop a wholly different approach to working with data.
Working with Haskell will result in developing some understanding of lambda calculus, which is relevant to all functional programming.
Many developers who work with Haskell also comment on the clarity of meaning and purpose experienced with reading Haskell. While this is subjective, the language itself tends to produce code that is very explicit and in many cases, obvious. No one gets upset when code is too obvious. Unironically, Haskell code tends to be very concise.
One of the most challenging concepts in Haskell is called a Monad. Monads allow developers to avoid typing excess code and string together multiple computations. The Haskell documentation frequently describes Monads as "a strategy for combining computations to produce more complex computations."
Monads are not entirely exclusive to Haskell, but Haskell is known as being a language in which they are well implemented.
-- FizzBuzz in Haskell
-- https://github.com/zenware/FizzBuzz/blob/master/haskell.hs
module Main where
fizzbuzz :: Int -> String
fizzbuzz x
| x `mod` 15 == 0 = "FizzBuzz"
| x `mod` 3 == 0 = "Fizz"
| x `mod` 5 == 0 = "Buzz"
| otherwise = show x
main = mapM (putStrLn . fizzbuzz) [1..100]
Resources:
While programming languages are simply tools and tools should not be blamed or praised in the place of those who use them, different tools do unlock new techniques.
By introducing yourself to new tools and the techniques they enable, you can become a more well-rounded and creative engineer. If you are curious and adventurous enough, you may even find language features and programming paradigms that you can bring back to your preferred language.
I'd love to hear if this list inspires you to investigate one of these five languages, or if there is one you think I missed! 🤠
Top comments (97)
First of all, I would like to thank You for writing this article. Secondly, I would also like to state that arguing about languages is beneath me and please don't get offended as I'm only writing about my experience and conveying my own opinion.
I still notice that many people perceive programming comprising Web only technologies like JavaScript, React, Vue, etc. On the other hand, C++ is considered the most complicated all purpose language that is mostly used for high performance and system programming.
First of all, C++ is not so great and you can say what you will, but template hell aside, C is much faster and cleaner language and if low level and embedded is your thing, there's no other language that will make you REALLY understand how memory, threading and CPU works.
If you are in academic circles, doing some extensive calculations, then GPU or OpenCL will be your best friend, and that is also where C is your only option. The only low level language other than C is VHDL, a relatively new language used for FGPA programming.
So called modern programming paradigms apply only for Web and Mobile world since nothing has really changed, apart from new buzzwords that are basically synonyms for algorithms and/or technologies that have been available for quite a while. There are exceptions of course, but in the case of C++, there is really nothing you can do in C++ that you can't do in C. I accept that some will argue against type safety of void pointers and casting issues but the whole point of low level languages is to learn how stuff really works. If you are aware of endianness, padding, byte boundaries and how pointer arithmetic works, you will begin to appreciate the gained knowledge which will outweigh the initial frustrations of C. GDB and Valgrind are exceptional tools and are only getting better (GCC/Clang fsanitize methods).
I welcome the advances in Web realm, but let's not forget that all that JS is compiled and prepared by Node.js, served mostly by some Virtual Machines running on some *NIX distributions, and ALL of that is written in C. Node.js is a combination of C and C++ but it's core part, libuv, is written also in pure C.
I admire people who are mastering JavaScript and Web technologies because, let's be honest, it's chaos out there. JS is constantly being updated and it's really hard to follow, so I applaud you guys and don't take this as me putting C on a pedestal. I'm just to trying to remind everybody that it took a great deal of knowledge to create such a stable and old language, not to mention compilers, optimizations, etc.
Thank You for reading,
DF
P.S.
Haskell is a special kind of beast :)
C is generally not considered to be a low-level language, rather assembly is intended with this term.
Calling VHDL new also sounds strange when it's from 1980. VHDL (1980) and Verilog (1984) are two hardware description languages. Their purpose is completely different from general programming languages and I would not classify them together with those. What could be said is that VHDL borrows syntax from Ada and Verilog borrows from C.
Hi and thanks for the history lession. I don't know much about VHDL, but I only used the word 'new' since it became more popular these days with increasing popularity of FGPA hardware. And I would agree that ASM is the real low level language, but let's put everything in todays context when everything is JS alike; in that case, C should be considered a low level language.
I always wanted to try and do something with FPGA, just for the fun of it.
C is a great language. I don't believe I said it wasn't, but I will say, not everyone should attempt to master C and it certainly (as some have suggested) is not the best tool for every circumstance.
I actually have written some C code and respect it as the defacto standard for applications where a small memory footprint is of the utmost importance. I do not disagree with you on the majority of your points.
I would have included C on this list, but I wanted to include Rust (which can serve some of the same needs as C) as this article is actually based on the five languages I'm most interested in mastering.
I have actually written a comment about that, and I agree that not everybody should burden themselves with C or C++.
Although I'm a C programmer and do mostly backend network programming involving raw sockets, packet capture, etc., I disagree when newcomers get advised to start from C language because they need to know how memory, cpu and whatever works at the basic lebel. That's great, but that's like saying I need to be a mechanic to learn how do drive. Since most of developments today is web dev which is done mainly in higher level languages like Javascript, there really is no need to burden yourself with all the complexities of C, C++ or any other statically compiled language with manual memory management. Unless you want to go in that direction like me for example or are attracted to embedded devices, stick to higher level languages. This is my opinion and in no way a professional guidance of any sort.
Also, learning all about memory, and CPU in the Von Neumann model is not necessarily reflective of modern computing models. Furthermore, it deprives us of the question of how high level programming should be done. Low level is not the most common paradigm for programming these days. Its more effective Software Engineering if we can hide away details of the architecture and the machine and let the language/platform deal with them. A great example of this is SQL, which although it has its problems as a language, is great at hiding away all the parallelism that goes behind it.
Rust replaces C/C++ on this list. You say there's no other language that will make you really understand how memory, threading and CPU works, but that's no longer true. Since we have Rust now we no longer need C or C++, unless it is to maintain/interact with existing C++ code.
Rust doesn't really replace anything. Still to this date all the important low level programs are being written in either C or C++.
There are plenty of important things being done in the Rust space. There are more than 400,000 line of Rust in Firefox, iirc.
OK please don't make this a language wars thread. I've never used Rust and although it might be awesome, it takes years for a compiled language to become trully stable and get close to being bug free. Firefox is not really a poster child of stability. The best test for any technology, a language in this case, is a test of time.
Rust could become the future C/C++ alternative, lest it become another ghost of a good project. Years ago it was D, now it's Rust; C and C++ aren't going anywhere.
Time is a ruthless judge and jury.
D is not a zero cost abstraction language like C, C++ and Rust are. I was just correcting you on the point that you made about C and C++.
I only mentioned it since it was highly praised not so long ago. What point was that? You mean the test of time point I made?
Ah, just this one:
"there's no other language that will make you REALLY understand how memory, threading and CPU works."
I was just correcting that because it's a common misconception amongst C/C++ programmers. For decades they've deflected competitors like Java, D and Go with the argument that they're nice programming language, but there will still be a place for C/C++ because of its direct reasoning about memory and its ability for zero cost abstraction.
Rust is the first serious competition to C and C++ in this regard. It is a full replacement of C/C++, it does not abstract away anything.
I would also argue your test of time point, but you said you don't want a language wars thread so I'll refrain.
Good point and appreciate the argument. I never claim to know everything and it's always useful to gain extra knowledge. Please comment on the stress of time test, I'm interested in your arguments regarding. What I meant with not wanting language wars is a thread along the lines of "A is better than C", without stating hard facts and reproducible arguments.
Thanks for demystifying Rust for me 😁
Well the argument would be that since Rust is built on LLVM, and actually maps quite closely to the semantics of C, there already is decades worth of production tested compiler infrastructure beneath it.
Of course there still are bugs from the rest of the architecture, but I'd recommend you check out the way the compiler is being built. It is a lot more structured and well organized than most other projects I know of (both open source and commercial), I'd bet we're getting to the point where a new release of Rust has more structured and well thought out decisions made on it then for example C++20 would have, but then I'm crossing into more subjective territory so I won't make any hard statements there.
Well congratulations for sparking my interest in Rust. I understand your LLVM argument in favour of Rust; it has its merits. Also, function arguments in Rust remind me of Pascal which was my first programming language, the one that got me hooked to programming. Who knows, maybe I will finally find a friend for my goold old C buddy 😁. I've done a lot of C++ and it was that final disdain that made me use C exclusively. I'm going to keep my eye on Rust, thanks.
Not all of them.
Sure, but if you want to solve real world tasks, just learn C and forget about the rest... meditate on that for a while, it'll help you grow.
C is a great language, but as the adage goes, if all you have is a hammer everything looks like a nail.
C is absolutely terrible for some problem spaces.
I find this comment incredibly ignorant of the history of the origins of Elixir's forerunner, Erlang, which was developed with the sole purpose of solving the real-world task: "Keep the majority of a telecom network running even when a part of it goes down, due to either maintenance, or outright catastrophe."
No amount of meditation on C will remediate that, because if it could, Joe Armstrong wouldn't have needed to invent Erlang.
The right tool for the right job.
I wouldn't try to saw through concrete with a toothbrush (even though it might eventually work).
C is great if you're going to do some kernel hacking or develop drivers and stuff like that.
For web programming and mobile programming C is not the right tool for the job and its quite outdated as well since it lacks support for the main programming paradigms in use today.
that's because the web is a poorly planned and implemented disaster.
Seems to be pretty successful to me, but I get what you mean.
Androthi,
The web may be poorly planned and implemented disaster.. but C wasn't going to make it any better. In fact, a lot of the security problems we have in OSes, and web services are caused by using C which is particularly vulnerable to buffer overflows and other dangerous hacks.
The study of computer languages is dedicated to creating more powerful tools to use to express our programs. Functional and OO (and other weirder ideas that have appeared throughout the years) are dedicated to finding succinct ways to write code so that we minimize dependence on architecture, can be more secure, reduce programming errors, while promoting things such as modularity and extensibility.
C was great to get people off their Assembler and Cobol addiction in the early days. But there are far better languages for HIGH LEVEL development today. And there also seems to be better languages for low level development these days as well.
(Note: I programmed in C/C++ professionally for over 10 years.. and still enjoy partaking now and then.. but its important to use the right tool for the job..)
C was awesome back in the 80s when it first became super popular.. we really enjoyed it back then. But we also enjoyed being able to move to real OO languages in the late 90s.
I myself think Smalltalk outdoes any language in existence today, so called "modern" languages are sad imitations that are overly complex (yes even Python and Ruby) and still not as powerful. But I guess I'm in the minority.
if you think you're in the minority, hold my beer:
C is showing it's age and may not be the language with all the bells and whistles programmers have been convinced are the greatest things since sliced bread, but the gist of my comment remains...
if web development was centered around systems programming rather than the scripting nightmare it is today, C would suit it perfectly and you wouldn't need the dozens of convoluted "technologies" that have to work together to get anything done.
i'm not a huge fan of C and we do need something better. many have tried, some have gotten close and others are in the works. i just don't think it's any of the ones you mentioned. and i certainly wouldn't touch smalltalk with a ten foot pole :)
the right tool for the right job? sure. if you spill water, you'll need to invent a sponge to soak up the mess faster, but that old rag can still do the job.
I'm a huge fan of C and use it exclusively these days, though I still like your comment due to good arguments. I hear that Rust might be an adequate replacement for C/C++.
Androthi,
yeah.. some early internet companies started out with C (like Amazon for example).. they quickly saw the light.
If you can do better, by all means, prove us wrong.
But you're kind of going against computer language research, and modern software engineering practices.
I don't know why is everyone so afraid of
C
. I am currently in embedded world where almost everything is done in C and haven't noticed any issues or complaints if proper procedures are followed. Of course, it's not as easy as languages which are hardware agnostic, but given the fast paced evolution of hardware, you can know runNode.js
apps even onSingle Board Computers
likeRaspberry
for example.There will always be fans and groupies of every possible language out there, that's just how human mind works, and affiliating yourself with your viewpoint proponents is our inherent nature.
I am still convinced that C is not going anywhere, and concede your arguments against it. Although, I don't see anyone rewriting
back-end
software to any other language any time soon, maybe never.In my opinion, C will stay here until
NLP
(Natural Language Processing) finally evolves enough to understandsemantics
, and from that point on, the mindset of every developer will evolve into something we cannot even conceive at this point in time. Whether the evolution of NLP will overcome this obstacle and get us closer to creatingAGI
(Artificial General Intelligence), this is yet to be seen.We can talk about the present, but I wanted to give you my take on how the future might look. AI may seem powerful now, but it still has a long way to go. Image recognition aside, human languages are still misunderstood and impossible for a machine to understand without the proper understanding of semantics.
I may have gone a tad too far with this; my intention was to mitigate the potential tensions between opposing language proponents :)
I have no problem with C.. I programmed for over a decade in C and C++.
But its not for web programming.. and its not ideal for all scenarios.
I'm not afraid of it at all.
I just think there are better tools for the job.
Of course it's not for web. Maybe with Web Assembly but I think Rust will take over in that specific area, maybe, who knows.
to be fair, C can't be included in a list of "languages that stretch your brain"
it can't be included because C is the granddaddy standard measure. all the other languages are compared to it.
for my list of languages that stretch your brain i would have:
Number 5 will not only stretch it, but probably also displace it 😄
i don't think rust is an adequate replacement for c/c++. it's a language with a very specific purpose.
it's great for writing security software, or software that needs to be proved. i think rust is more in competition with ada. and i kind of prefer ada.
rust just doesn't have the ... agility that C has.
modern software engineering practices gave us the likes of facebook and twitter. both of which have a garbage code base.
just because something manages to steam along as long as you throw the latest bit of hardware at it doesn't mean it's good engineering.
I think I mentioned that once. Just because we have more powerful hardware doesn't mean we have to write less efficient software. Nobody cares about optimisations and memory efficiency these days. I used to play great games on my Atari ST with 1Mb of RAM. It sounds like scifi today, to have only 1Mb of memory.
should have figured.
i started out on the c64, then on to the amiga. in my experience, people who started out with those early systems grew to appreciate hardware limitations and getting every last bit of processing power out of them.
now with everything practically being emulated and a dozen CPUs living in each computer, programmers don't care about resources or efficiency. as long as they can roll something out quickly and it functions relatively fast.
The good old days:
The evolution of a programmer
Damir Franusic ・ Jul 24 ・ 6 min read
Exactly ☝️
That's a nice list. I'm stretching my brain with some Perl 6 programming. Perl 6 is very expressive and includes features like:
Here's my version of the FizzBuzz written in Perl 6:
My boss is a Perl developer, or at least was before he started writing Ruby, I really appreciate Perl's expressiveness. I've thought about picking it up to build some fun tools before! Thanks for including a code snippet!
Perl 6 (perl6.org) belongs to the same family, but it's a totally different language. Much more expressive, too.
I hope this list receives massive boosts. The line of reasoning for each language is unique, well-considered, and sound. I read a similar post yesterday, extolling Python, C++, Java, JavaScript, and Scala, with the rationale for learning each language essentially boiling down to "it's popular" or "it's easy to learn"... Java was in both categories, without any sense of irony on the "easy to learn" aspect.
While I vastly prefer Elixir's soft approach to type enforcement over strict statically-typed languages (declaring a
@spec
for a function allows static code analyzers to warn you when an input or output might not align with what you've said it should be) (also, pattern-matching on function parameters is, in a sense, a means of type enforcement), you've convinced a stalwart proponent of JavaScript's typeless wilderness to dip his toe in TypeScript, where many TS evangelists have tried and failed 👏Oh, I may be wrong on this, but I think you can clean up the fizzbuzz expression you wrote for Elixir, slightly... if you've already tried this and it came back with an error, please do let me know, because I'm actually curious and not near an
iex
prompt at the moment 😅I didn't write it, it's from a GitHub repo, but as soon as I'm back to my laptop I will write an Elixir FizzBuzz solution just for you 😉🤠
Ahh, that makes sense too 😅
A good list.
As a Clojure fan I'd recommend it or any other lisp if you want to learn new concepts. Treating everything as data is mind bending in all the right ways.
I'm learning Rust and I also program microcontrollers with C. I agree with you that Rust is the better recommendation given the intent of your article. It brings some novel concepts to the table that C and C++ do not.
In fact, the first thing came to my mind when I see the article title is .. Clojure !
Clojure is a language I'm interested in for sure!
I think you should add Prolog to your list. That is a language that uses pattern matching to a greater extent than the languages you mentioned and also really forces you to look at programming in a completely different light.
I'll definitely give it a once over! Thanks for sharing!
To stretch the brain more - I would advise to write your own compiler or language.
Yes, this is a big job!
One of my IT professors, who is already 70 loves to do that during his summer holidays.
At summer he goes for a 1-month rafting trip, takes his laptop and writes a new compiler! 👴👨💻
It's in my todo list, hopefully not the bucket list 😂
That’s great, wish you to succeed!😊
Do you already have the ideas on your language?
Not really but I'm sure it will come to mind one day. I have written parsers, lexers and interpreted DSLs (Domain Specific Languages), but never really needed to go one step further and create the actual compiler. Even if I find the time and stamina to try it, it will serve no other purpose, apart from making me feel more competent about my skills.
All of this is based on the assumption that I emerge successful from this endeavor. There's always a chance of everything ending in disaster with me crying myself to sleep surrounded by wild hordes of bugs which have found their new spawning ground, my brand new co-called compiler. 😊
You have a really wide experience!
You are right. Usually such experiments with compilers is something that happens in academic environment. Actually, I worked on my DSL being a post graduate and there is no guarantee it will see the real world one day.
But, anyway it always makes me feel proud of my self! 😊
That's a project I'd like to complete this year actually!
That’s cool!
I had some experience in developing a programming language, but that was the DSL (Domain Specific Language).
Share with us your progress, very interesting to know.
Nice article, I would have chosen the following construct for the Rust example since pattern matching is more idiomatic in Rust than a bunch of if/else.
Something like this :
Its not quite as compact as your example but you can remove a level of indentation by just having one liners like
x if x % 15 == 0 => println!("FizzBuzz"),
if that's your thing.One advantage to pattern matching in Rust is that it forces you to exhaust all possibilities when comparing values. This avoids forgetting the
else
or a particular case for a number.Excellent article !
Thanks for sharing! I didn't actually write the FizzBuzz solutions, they are from a GitHub repo. I appreciate your input though, super useful 🤠
You should cite your source in the article.
Way ahead of you, I already did! It's in a comment in each snippet.
I love this article. I've touched all of these languages at least once with the exception of TypeScript which I would like to try. I really liked Elixir and its Supervisor tree, it definitely stretched my brain. I put in a strong effort to get good at Rust (the borrow checker won the battle, but the war is far from over). I couldn't stretch my brain far enough to grasp Monads and Functors for Haskell though. That one finally broke me.
I hope these languages keep growing. I'll keep them in my tool chest.
I'm always sad to see people get tripped up by Monads, and especially by Functors. They're necessarily simple concepts that are almost always explained poorly.
Functors are things you can map/apply a function over. Exactly no more, and exactly no less. Lists are Functors because you can apply a function to each element of a list. Maybe is a Functor because you can apply a function to a single element after checking if it exists. Functions are Functors because you can apply a function to the result of a function. 'Void a' is a Functor because you can apply a function 0 times to something that does not exist. The Functor typeclass exists so that we can say that we don't care which of these (or other) things we're dealing with. If you have a structure, and you can write some plumbing code to take a function and apply it around your structure, you have a Functor. Note that something either is or is not a Functor, it's not actually up to you to decide, just like you don't get to say the number 3 is even. It is, in essence, simpler than actually thinking about the particular structure you are mapping over, because that particular structure has additional implications beyond what Functor implies.
Monads are not quite as simple, but almost. They're usually explained in terms of return and bind on some bizarre example ("Monads are like burritos!"), but bind is a more complicated operation that's implemented for performance reasons, rather than ease of understanding. Functors need one thing (mapping) but Monads need 3. First, they need Functorness - if it's not a Functor, it can't be a Monad. Second, they need to be Pointed, or injectable - if you have some random value, there should be a trivial way to cram it into the Monad and this is currently called 'return', but in the future might be called 'pure'. Lastly, they need Join, or flattenability. The injectability means you can just keep wrapping more and more layers of the Monad around a value - you can have the number 1, a single element list containing the number 1, a single element list containing a single element list containing the number 1, and so on ad infinitum. Join does the opposite, save that it can't get rid of the last layer - you don't need to know how to 'exit' the Monad, just simplify it. In Haskell syntax, that means you know how to go from [[1]] to [1], but you don't need to go all the way to 1. That's it, those are the three operations that make a Monad. There are some rules about how Monad instances should behave - Functor had them too but the type system is good enough that you can't accidentally break those. The rules are 1) that 'return' must really be trivial - if you stack a bunch of layers with return, then join them back down, nothing should change and 2) if you have a bunch of layers, the order you join them in should not matter to the final result. In terms of list, return makes a single element list, and join is just a single layer flatten - and it doesn't matter what order you flatten things in, you always get the same list at the end. In equational terms, 'x == join (return x) == join (fmap return x)' and 'join (join v) == join (fmap join v)'. If this sounds scary because of 'fmap' here, just try to remember that by using fmap we remove all possible considerations except that it's something you can map over - it is mapping distilled to its most basic possible form. Individual Monads have their own interesting behaviors, but those have nothing to do with Monad itself, which is nothing more than what I have described here. Monad is ultimately a fairly simple concept that gets bogged down with specifics that you don't need to think about for the core subject. Monads are implemented in terms of bind, where 'm >>= f' is ultimately the same meaning as 'join (fmap f m)', but the latter possibly constructs and breaks down an intermediate structure, and so can be prohibitively slow in practice.
Typically, the aha moment for Monads is not when people grasp the complexity, but rather fully realize they can let the complexity go.
Thanks WarDraft! I'm still unsure about Monads lol, but your last statement put me at ease. Maybe it's best to not try so hard to understand it, and let it show me 👍🏾
Great article!
We had a Programming paradigms course this semester where we did Prolog, Py, Huskell and Scala (though we went through most langs in an theory overview including all the ones listed in your article).
That was probably the most fun I had programming in the three years since I enrolled in CS. The different requirements the languages themselves put in front off you are a real brain stretch, especially if you've been used to and locked in a single way of doing things (as most people inevitably are due to the nature of CS studies / work on a particular codebase at work). All in all, I find that these paradigm shifts are the best thing one can do to improve their problem solving (which is the most important skill after all).
Thank you very much for sharing. :)
I really don't understand how you can not to mention Smalltalk. You even mention Alan Kay and Ruby, yet you don't mention Smalltalk? Seriously? We are talking about stretching your brain, not learning a programming language for looking a job.
Beautiful thing about dev.to, you can write your own list. 😉
Seriously though, this article is largely based on my own preferences and I like Ruby.
Sure. But I thought that "stretching" was a bit more general and not your own preference. Smalltalk doesn't everything differently. It gives you a new perspective. That's why whether for good or bad I cannot think of anything better than Smalltalk to stretch your brain.
Smalltalk is great; I'd love to learn more about it. Write an article explaining some of its features. I'll read and probably share it!
I didn't include it in this list because it's not something I want to learn right now and I write articles mostly as reminders to myself, I don't really care to be super objective in them (unless I'm modeling a thought process in which that is important).
In this case, these are languages I want to learn more completely that I think will help me to understand new concepts in programming. I tend to be more pragmatic than academic, so it makes sense that I focused on languages that are a bit more mainstream than Smalltalk at the moment.
Thanks Jacob for the reply. Yes, I think the subject of the post was what confused me and made me thought it was something way more "objective". But I totally understand your point and being pragmatic.
I am writing a lot of blog posts about Smalltalk (almost all of my blog) but none is just about the language... too much out there explaining better than me :)
Anyway, that aside, it was a good reading and thanks for putting it together!
Good article! Although, I wouldn't say that learning Typescript is a brain stretcher. If you're a web dev and familiar with JS, your not learning anything new, but more "syntax" for the language (potentially more headaches as a project's complexity increases too :).
As an aside, nice to see Haskell/Elixir getting mentions.. Scala/OCaml/C#/F#/Clojure are also worthy contenders in a similar vain.
Somebody already mentioned Smalltalk. If one really wants to understand the Object Oriented paradigm, this is a great start.
Why learning Smalltalk can never be a waste of time
Smalltalk is not just a programming language
Why Aren’t People Using Smalltalk?
From there, you can browse around other articles on Smalltalk by the same author.
Next, Erlang is (like Smalltalk) one of the few languages that are pure Object Oriented. "Huh? It looks functional to me", I hear the noise your brain makes. Well, it looks functional, but functional and OO do not bite each other. They can be in the very same concept.
Interesting thread on Hacker News
Object Oriented Programming: The Wrong Path?
Smalltalk had all the stuff people consider "cool" today.. including Blocks (aka. lambdas) that really looked much slicker than the Lispy counterparts. Smalltalk was heavily influenced by Lisp. Very elegant language. I particularly liked the IBM variant.
But Smalltalk was poorly marketed and sold, and very expensive. There weren't free versions for college kids. And some of the versions were stuck in UIs from the early 80s rather than moving on to be more like Windows or other modern UIs. By the time people were ready for it, Java came and stole the show and dug the final nail in the Smalltalk coffin.
The final nail in Smalltalk?
Smalltalk is still alive! Even better, there projects being build with Pharo, Seaside and Teapot (I didn't made up these names).
Pharo is very easy to install, browse around and use to follow some introduction tutorials. It works great. It shows already how different the whole approach to programming it takes. But it can take some time to wrap the head around certain things to really grasp the philosophy of Smalltalk.
Sure! I'd advise anyone specifically interested in learning OOP to learn some Smalltalk.
Personally, I didn't include it in the list because it's not a language I'm focused on learning right now and generally I treat blogging more like a notebook than anything.
Great feedback though, and thanks for sharing those articles I've read one or two of them but I'm looking at the others now 👍
It's interesting to me to see Typescript and Haskell on the list together. As someone who is working on learning Haskell while using almost entirely Typescript at work, Typescript feels entirely lacking as compared to Haskell.
Typescript's static type checking fixes a lot of type problems in regular Javascript, but falls flat when attempting to work with real data, with many casts, optional fields, and "any" types making their way deep into the program as it develops and ruining the functional benefits of static typing.
Haskell's strict separation of IO from pure functional removes a lot of unexpected edge cases. There's also the common occurrence where, if your complete program typechecks, it's likely to actually do what you intend.
I guess my point is that these languages stretch my brain in different ways: Haskell engages me with interesting mathematical ideas, but Typescript makes me wish I was writing Haskell.
I know I'm going to be roundly laughed out here, but a lot of the languages we see around us are the result of people trying to come up something better in terms of their perception to new tools available.
This is an old language, and one for the most part a forgotten one, ( especially after reading the comments about smalltalk ) but its still a 'secret sauce' used by some surprising majors in their early conceptual labs. ( maybe because it's in Reverse Polish notation, trying to disassemble by industrial spies it produces nonsense.) I liked it for producing ultra quick algorithm design and proof of concepts, but the ever growing provision of 'playgrounds' are replacing that need.
Yes I gave it away then. The language is Forth. If you're done with mind-stretching, finishing off the smorgasbord with a dip into it is seriously mind-calming. Originally designed for embedded astronomy electronics, it gives a swift path into meta-programming without even realising. Everything else is there.
There is a saying: " If you seen one Forth, you've seen . . . one Forth!" that's because its extensible in so many ways, that a lot of the newer languages discussed are doing what all these scattered Forths did anyway.
As a side note in closing, we often like to romanticise Ada Lovelace as a hero, being the first programmer as C Babbage only designed the system. We have an equivalent hero alive today in Elizabeth Rather, she was the first to actually implement Forth in code as it's founder Chuck Moore was more the devisor while they worked together in developing it. And she's still at the helm. Another parallel can be found in Delia Derbridge, the actual technician/musician who assembled the Doctor Who theme after Ron Grainger left the specification on her desk before going on holiday.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.