Functional programming just has something magical about it that really draws certain kinds of people in.
I wonder if it has to do with the fact that, when you play inside the boundaries of what a functional programming language can do, everything feels so neat. So tidy. Like a game. Or using lego bricks. It almost feels insane to do things any other way.
But then again, most problems live in the real world, where things are not neat, or tidy, or like a game. I wonder if this is why you tend not to see functional programming languages more broadly used...?
and I think sometimes certain languages fit the solution space better than others.
I think it might have to do with expressiveness.
If I want to write a CLI program and parse a bunch of arguments in different ways, I think python + argparse is a pretty effective way to do that.
At one point, I think perl was the most generally expressive language I'd ever used. I could think of something, and then dump what was in my head into perl with little or no friction. do until! unless!
(of course, the practical aspect of that was that if it is expressive that way for everyone, you will have to understand how someone else thinks to understand their perl program)
> I wonder if this is why you tend not to see functional programming languages more broadly used...?
The overarching problem is that functional programming trades extra thought now for extra benefit later.
Inexperienced programmers hate functional programming because they like "magic". They are having a tough enough time just getting the task at hand finished and the more stuff done for them without thinking, the better.
Inexperienced programmers don't want to think about multiple threads. They don't want to think about the event loop or sockets. They don't want to think about the state of the protocol and why it shouldn't update multiple steps. etc.
The only way for that kind of magic to happen is to have a bunch of implicit state that sits invisibly in the background. It's either global or part of a single mega-struct that might as well be global.
However, if an inexperienced programmer sticks around long enough they eventually run into a Heisenbug that is difficult to replicate. In order to run down the bug, they start having to isolate everything. Suddenly, the words of the old greybreard start coming back: "Immutable is good" "Time needs to be an explicit part of your state" and "bytes in, bytes out--putting the bytes on the wire is a different function" and ...
At that moment, they become an acolyte of functional programming and now qualify as an experienced programmer.
Not all experienced programmers become functional acolytes. See: Ken Thompson, Donald Knuth. They like procedural programming and prefer to model programs with imperative, mutable state, rather than pure functions that map one type to another.
Richard Stallman is known more for his clarity of thinking about individual freedom and its likely abridgements that can arise as a result of using commercial software, than his chops as a coder. I could be mistaken, though.
It strikes me that some people think in data, others in processes.
Personally, I need transparency and understand everything step by step. But there are those that threat a function/process like a blackbox and just build pipes based on some defined axiomes. The latter also seems to do quite well in math.
I like OOP precisely because you can just treat any object like a black box. You don't need to fully understand what the object does at all times.
The way my brain works is by turning all problems into spatial problems. Programs take the form of a large graph with a function or other operation at each node. Generally, I'm modeling data flow through the graph. I can keep a fair amount of detail associated with any node, but it takes effort. There's a lot of information floating around.
OOP just kind of naturally falls out of this kind of thinking. By collecting parts of the program into discrete objects that do their own thing, large parts of the graph can be collapsed into a single node. Data flows into an object, data flows out. No need to spend the mental effort of knowing what happens inside the box. I can just simply trust that I wrote an object to do what it says it does.
Of course this approach often fails and I have to be much more thorough. If I can focus on a small section of the program, the graph becomes almost an arbitrary syntax tree. The past couple of weeks I've been way in the weeds with a microcontroller. At some point I've started modeling parts of the program in terms of assembly instructions and CPU implementation details.
1. Until now most functional programming languages have had abysmal syntax. I'm sure I will get downvoted for this but have you seen Lisp? I do not want to program in raw AST. ML is also pretty bad. Honestly the hardest thing learning OCaml was figuring out where to put the brackets and semicolons. I am 100% serious. (Well, that and fighting OPAM bugs.)
Rust is functional but the syntax is 10 times easier to read and write. I think other languages will follow.
2. Functional programming has been synonymous with pure functional programming due to Haskell. Honestly I didn't even realise there were impure functional languages until relatively recently. I thought to be "functional" a language had to be pure.
Again Rust is functional and impure.
So I think it's really that most "practical" or "engineering" languages just happened to be not functional until now because the idea of functional programming was hidden in weird and difficult to read academic languages.
There's clearly nothing intrinsic to the functional paradigm that would mean it can't be used in the real world (otherwise Rust wouldn't be so popular).
> I'm sure I will get downvoted for this but have you seen Lisp?
How much time have you spent writing in lisps?
I'm definitely an OOP person, but I spent a couple of years writing Clojure. After a few hours of working in it, the syntax just... disappears. I installed two tools in vim to help: one colored parentheses to match corresponding pairs, and the other inferred parentheses from indentation. After a week, I removed the first because I realized I literally never looked at them. Ever.
The reason I didn't fall in love with lisps is because it's just hard for me to work in them. Yes, I'm _very_ productive once I get into flow state - but it took about a half hour each session before I got there. There were many days where I never got into that state for more than a few minutes here and there. It was a terrible experience as a result.
With Python - and other OO languages - I can look at some code and almost immediately know what it does. It's just not like that for me in lisp.
What did you install in Vim for inferring parens from indentation?
I use an adaptation of parinfer I found in github. It required a bit of tweaking , including adding a keybinding to turn it off, because sometimes it fights what you are trying to do. Its opposite mode (indentation from parens) does not work at all.
> hour each session before I got there
That could just be the Clojure, doing everything with immutable sequences.
If the obvious way (at least to you, if not generally) to express something is OOP with mutable classes, then you have to solve a puzzle before things start to flow.
> What did you install in Vim for inferring parens from indentation?
It's been years now, but I believe it was "parinfer". This specific plugin might not be it, but it looks very similar at least: https://github.com/gpanders/nvim-parinfer
I upvoted you because I don't think Hacker News should become an echo chamber of the same few opinions, but I disagree with what you say here.
I wouldn't call Rust "functional and impure." It has pattern matching (like in ML), and it has traits (which are reminiscent of Haskell's typeclasses) instead of object-oriented classes (like C++), but most programming in it is very much centered around mutable state and pointers and memory, like a higher-level C; hence, it's impure and imperative, not functional.
A functional and impure language would be more like OCaml, Standard ML, or Scheme. Those all give you unrestricted access to exceptions and mutable cells of memory without restricting it behind a layer of monads, like in Haskell. They just don't really encourage it.
> Rust is functional but the syntax is 10 times easier to read and write. I think other languages will follow.
People complain all the time about Rust syntax looking cryptic and difficult to read.
Also, I'm familiar with both Haskell and Rust syntax, and although many would disagree with what I'm saying here, I don't think Haskell syntax is any harder to read than Rust's. And Standard ML even has much simpler syntax than Rust (although it's much less alive than OCaml, whose syntax is a bit more complicated). I really think it's a matter of what you're used to.
I think you're making the pure=functional mistake like I was. Rust is almost identical to OCaml in terms of functional style. Which is no big surprise given that it was heavily inspired by it (and the first compiler was implemented in it). I think the only major difference is the lack of currying.(which IMO is an elegant-looking anti-feature).
> People complain all the time about Rust syntax looking cryptic and difficult to read.
They're talking about all the borrowing, lifetime and generics syntax. Not the basic blocks and semicolons.
I think we just define functional programming differently. How do you define it?
Also, I just noticed this part again:
> Honestly the hardest thing learning OCaml was figuring out where to put the brackets and semicolons. I am 100% serious.
Unironically, I'd recommend Haskell, or another programming language with similar whitespace-sensitive syntax. I'm more familiar with Haskell than OCaml (though inexperienced in both), and the semicolons and other delimiters actually got me as well.
> They're talking about all the borrowing, lifetime and generics syntax. Not the basic blocks and semicolons.
That's half the syntax to get confused about. But, ignoring that, people also get confused by the implicit returns at the ends of blocks.
I read a lot of articles like this, and it's usually mentioned that their preferred language is expressive. Here it's mentioned as a dig against the top 10 languages, basically saying that they lack expressivity
> make the language and syntax as simple as possible, and then even simpler at the expense of expressivity
I understand why people say this because you can write these small highly condensed statements which would take a lot of code otherwise to do. I think it's probably the wrong word though. These languages generally prevent you from manually managing memory, which ironically makes expressing some designs or patterns impractical. If you want to express say writing a performant garbage collected language or something, a language like c or c++ is ironically more expressive than these other higher level functional languages with a runtime gc.
> Other languages I enjoy include Haskell, Elixir, and Rust. [...] Rust is great because it has a phenomenal type system with good type inference; it’s metaprogramming story could be improved though.
I agree with the author about Rust in that it has a beautiful and expressive type system. The fact that it can be used for systems programming, has a modern package system, and can be deployed as a single static binary are bonuses.
Rust is a perfect little Go/Java replacement for microservices and web servers.
I learned Rust to the point of competency (but I'm certainly not at the point of proficiency) because it seems likely that knowing it will be helpful in terms of career development.
But I have decided that I hate it enough that I wouldn't accept a job that required me to do much with it. I would be unhappy in such a position.
It's an unusual stance for me to take -- I am proficient in a number of languages that I'm not that keen on, but can tolerate them for a paycheck. For whatever reason, Rust is an exception. I'm not sure why.
Personally I don't think it will be helpful for career development. I'm never going to work in a space where Rust will be useful and it would probably be a mistake to choose it. But I'm just a Java dev /shrug.
I consider it important to my career to be sure my skillset doesn't get stale[1]. I don't bother to learn everything that comes down the pike (who could?), but I do keep an eye on things and if it looks like something might end up being in demand, I'll learn it. I don't always forecast correctly, of course.
But I'm a programming polyglot. Learning new languages is pretty easy (if you already know the paradigm of the language, then it's just a matter of syntax), so why not?
[1] It's important to me mostly because learning a new language or other skill often gives me a new understanding or insight into programming overall. Also, having a wide skillset makes me qualified for a wider selection of jobs, making it more likely that I can find one that excites me in some way.
> Yet most of those are written in Go. In fact, the majority of the devops tools themselves (podman, k8s, etc) seem to be written in Go.
> Why do you think that is?
Because time travel, as far as we can tell, is not possible.
At least in the case of Kubernetes, Rust 1.0 wasn't even around until the year after it was first released (Kubernetes 2014, Rust 1.0 2015). It also came out of Google and Go was one of its blessed languages at the time (and today). Given Rust 1.0 wasn't out yet, I'd be surprised if it got more than five seconds of consideration by the team developing Kubernetes, if it was even on their radar at the time they started development.
It's fair to have an opinion, and that may be why Kubernetes hasn't been rewritten in Rust, but I answered the question of why it wasn't written in Rust. It wasn't an option at the time (again, time travel is not possible).
K8s was absolutely built using exciting tech....Golang was hot off the presses. The brand new hotness. Google's internal Borg was C++, so the boring choice was C++ which wasn't chosen. Also they were google employees, which also adds a bit of bias in selection I would imagine.
This is more of a style thing than anything else. Nothing stopping you from writing Python in an idempotent and functional style. I do it all the time.
The entire language is statement based, not expression based. Lambda functions are limited to a single expression. Weird special snowflake syntax for if expressions and array comprehension. Etc.
I think the point the author is making is: unless you control all the code you're calling, in a language without immutable datatypes, you can't be sure the other functions don't change your data.
I think this is a very unproductive and pedantic take of functional programming. Inside the function, all things being equal, the implementation isn’t important. The important thing is that it’s isolated, self contained and does not perform I/O
I fully agree, you will hate my 2 favorite languages. One of them has received a lot hate over the many decades from almost every academic person. The other one has only started getting hate over the past 10 years.
The other is c, which I went to in the 90s, that seemed to have started getting hate from everyone these days :) I prefer the K&R dialect is the version I started with.
I struggle to take anyone very seriously that expresses a profound negative opinion about C - it is still so ubiquitous and odds are overwhelming that the person expressing this uses somewhere in their stack many libraries written in C anyway.
I'd wager this is coming from the Rust ecosystem rising in prominence the last 10 years and Rust adherents being really passionate about that (cool! I take no opinion either way, please don't savagely downvote me).
I find all such debates tiresome, I am much more interested in the why of doing something than the "how." A programming language is a tool to me, nothing more. If the tool sucks I will choose a different one and probably feel zero emotions about it, but acknowledge not everyone is this way.
> I struggle to take anyone very seriously that expresses a profound negative opinion about [a language that] is still so ubiquitous and […] the person expressing this [probably] uses somewhere in their stack
Are you saying that because C is popular and widely used, someone can't credibly hold a negative opinion on it? Are we required to think highly of things because they are popular?
It’s very interesting you find my comment as prescriptive when I’m merely pointing out that C has historically been a good tool. In this person’s opinion, it sounds silly when people try to tear it down, often with some agenda. I mentioned Rust because it often seems to come from a very passionate camp there (again, cool! nothing wrong with that). As I said, programming languages are tools, some tools are good for one job and not another, and prescriptivist talk about such things I immediately tune out and cannot take very seriously.
Luckily my opinion doesn’t matter and can be ignored.
>I struggle to take anyone very seriously that expresses a profound negative opinion about C - it is still so ubiquitous and odds are overwhelming that the person expressing this uses somewhere in their stack many libraries written in C anyway.
I like C, and I do think the hate mostly comes from the loud zealots in the Rust crowd, but this doesn't make sense to me. I hate car-centric planning, the fact that it's ubiquitous and that I drive around my city doesn't really affect the validity of my opinion.
>I struggle to take anyone very seriously that expresses a profound negative opinion about C
Those OpenSSH vulnerabilities really get stale you know...
>The net effect of exploiting CVE-2024-6387 is a full system compromise and takeover, enabling threat actors to execute arbitrary code with the highest privileges, subvert security mechanisms, data theft, and even maintain persistent access.
if {"Bjarne Stroustrup:
There are only two kinds of languages:
the ones people complain about and
the ones nobody uses."} == True &
{"Your favorite programming language is probably used a lot"} == True then:
return {"Must hate and complain about your programming language"}
> I could tell similar stories for other languages that I don’t like programming in. These languages include JavaScript, Go, Java, and C++.
...
> The thing I hate about all of the languages I listed is their emphasis on mutation. When I call a function and pass it a list or object or whatever, I have no guarantees about that thing’s value when the function returns.
This is not true for C++, where the 'const' keyword allows you to disallow mutation. Perhaps the author would complain that this behavior isn't the default, but the functionality exists.
int foo(const int &x) {
int &y { const_cast<int &>(x) };
y += 1;
return y;
}
It may invoke undefined behavior if the original int was declared const, but this still compiles with no warnings on GCC with -Wall -Wextra.
It may be really bad style, but not mutating const references is not enforced by the compiler. Hence you aren't guaranteed that your const references actually stay unmodified if you pass them to a function.
Functional programming just has something magical about it that really draws certain kinds of people in.
I wonder if it has to do with the fact that, when you play inside the boundaries of what a functional programming language can do, everything feels so neat. So tidy. Like a game. Or using lego bricks. It almost feels insane to do things any other way.
But then again, most problems live in the real world, where things are not neat, or tidy, or like a game. I wonder if this is why you tend not to see functional programming languages more broadly used...?