
Why learning Haskell/Python makes you a worse programmer (2006) - mrkgnao
http://lukeplant.me.uk/blog/posts/why-learning-haskell-python-makes-you-a-worse-programmer/
======
jarcane
I know exactly how he feels. This is basically the experience I had when I
moved from Python to functional languages and it finally "clicked" how much
more productive I could be in a Lisp or an ML.

Where I differ somewhat is that for me, it saved programming as I knew it. I
wouldn't be a programmer right now if it weren't for discovering Lisps and
MLs.

I fecking hated writing spaghetti OOP and tedious imperative loops. Mainstream
programming languages are built on the lowest common denominator and the
result is that as a younger person looking at the possibility of getting into
computers as a career, I was scared off by the amount of willful tedium that
seemed to define professional coding at the time.

Today I work in a Clojure shop, and if I didn't, I'd be very wary of looking
for employers that expected me to use inferior tools simply because they did
not understand more efficient functional ones.

It reminds me of some of the terrible kitchens I used to work at where I'd be
expected to do things like cut meat with a cheap paring knife because the
employer felt that a real chef's knife was "unnecessary" or "too expensive". I
quit those jobs, and frankly, I wonder at programmers who don't have the same
respect for their craft when it comes to programming tools.

------
na85
The smugness of Haskell evangelists is what keeps me from using it.

I swear, the first rule of Haskell is to never shut the fuck up about Haskell.

~~~
lmm
I never wanted to be like that, but it wears you down constantly seeing people
complaining about problems that are trivial, or going gaga over some "new"
feature in a trendy language that's a trivial special case of something
Haskell has had for 20 years. You get tired of telling people the same thing
every day and it never gets any better. Eventually you start just treating the
superiority of Haskell as fact, because it's too tiresome to be constantly
pretending that other options have their merits when you know they don't.

~~~
dozzie
Actually, much better approach is to shut the fsck up and write something
useful. Funny how Erlang crowd doesn't show that much of smugness when it
comes to parallel/concurrent programming. I've only seen two Haskell programs
that were at least remotely useful to me (one being Pandoc), and then again,
those programs had awful size of the binary and atrocious memory requirements.

~~~
MustardTiger
>Actually, much better approach is to shut the fsck up and write something
useful

No, it really isn't. What is the goal there? To prove you can use a general
purpose language to write software? There's tons of software already that
proves that. How many haskell projects need to exist before it has proven
itself or whatever it is you are expecting from this? If I write enough
haskell software, the industry will just suddenly stop using bad languages to
write bad software and _poof_ care about quality miraculously? How is the
industry supposed to know I have written this haskell software if I am not
allowed to talk about haskell, or writing software in haskell, or how good
haskell was for writing software when I used it? And why is haskell the only
language where nobody is allowed to talk about it or they are variously
branded smug, arrogant, academic blowhards, etc, etc?

------
tominous
I feel the author's pain. I had a short consulting gig recently where I was
asked to speed up a simulation job written in Python by a mechanical engineer.
Smart guy but not a programmer, so the script was full of global variables,
side effects and imperative loops.

I parallelised the script, which is pretty easy in Python but involved
refactoring into a more pure functional style. I abstracted out the algorithms
and added in some persistent memoization as a bonus. It was clean and did what
they needed, but... unfortunately was now completely unintelligible to the
engineer who wrote it.

When I was asked back 6 months later to help again, they had reverted to using
and modifying the old script. This time I kept the changes to the absolute
minimum.

~~~
adrianN
You lost the opportunity for recurring jobs every six months.

------
lawl
I know this is 10 years old, So the more interesting thing to me is that these
days you can do this functional style in most languages, even Java!

    
    
        foo.stream().filter(s -> !s.isEmpty()).collect(Collectors.joining("\n"));
    

So I'd say it didn't make them a worse programmer, it's just that the
languages were/are behind.

Edit: Yup, forgot to map the description, but I'll leave it now.

~~~
teh64
You forgot the map operation (and I would also filter out nulls): (just to be
pedantic)

    
    
      foo.stream()
         .filter(s -> s != null)
         .map(s -> s.description())
         .filter(s -> !s.isEmpty())
         .collect(Collectors.joining("\n"));

------
d--b
Where it does make you a worse programmer however, is when you don't realize
that using the join method on an iterator means that you are going to
concatenate a whole lot of strings, while in most cases, you actually could
know the size of the final string from the beginning, and you don't need to
allocate a whole bunch of arrays in the process.

These idioms have a complete disregard towards performance.

~~~
lmm
If you don't profile your code automatically on every build then you have no
business even thinking about such things. And if you do, that will alert you
as to whether it's a problem or not. Let the computer do the bookkeeping for
you, that's what being a programmer is.

~~~
d--b
I am simply saying that automatically choosing the nicer looking code just
because it's nicer is not always the proper option. Being a good developer
implies knowing when you're making a readability / performance tradeoff. If
using idioms makes you lazy to the point that you no longer want to write more
efficient code, then yes, it's making you a worse developer.

~~~
lmm
Laziness is one of the three cardinal virtues of a programmer. In my
experience thinking you know the performance characteristics of any given
piece of code is always a mistake. It's certainly not true that functional
idioms in general perform worse - e.g. map/reduce style can be automatically
parallelized, making it more efficient on modern multicore machines than
explicit loops. If you know you're writing for a specific computer you can no
doubt do better by using assembly, but functional code in general is more
adaptable to the unknown future, because it tends to require specifying less
of the details.

~~~
d--b
Look, I am not here to say that functional programming is bad, I really enjoy
using these idioms. I am just speaking from experience. Since Linq has come to
C#, I see things like this in my workplace:

    
    
        VeryLargeList.Select(x => x.Blah).ToArray()
    

And people are wondering why they get OutOfMemoryException.

Before linq, people would just loop, and the array would not have to be
allocated dynamically.

All I am saying is "more abstraction may lead to performace issue, and people
should be aware of it"

~~~
lmm
There's no reason that should use any more memory than an explicit loop. Maybe
the particular implementation in C# does, but that's an implementation
problem, not a language problem.

~~~
d--b
That's my point: the language cleanliness may obfuscate dirty implementation
details, and a good developer should know what these are.

Another example, when you do this:

    
    
        SuperLargeList.Where(x => x.Blah).ToArray()
    

There is no way for the compiler to know whether the output array will have a
small size or a large size, and so it will choose one or the other assumption
(dynamic vs fixed allocation). The language chooses for you how it implements
things, and this is all fine as long as you know about it, and as long as you
can do something about it in the case when you need to optimize.

~~~
lmm
> That's my point: the language cleanliness may obfuscate dirty implementation
> details, and a good developer should know what these are.

So what, we should write everything as CPU microops? A good developer should
be capable of looking at that level, sure, but it shouldn't be the default;
most of the time the computer is better at judging these questions than the
developer.

------
dozzie
> [M]y experience with Haskell means that I now see potential bugs everywhere
> in imperative code. [...] Now I know there are other ways of doing these
> things, I find it difficult to be satisfied with any of the code I write. I
> am constantly aware that I am writing traps that other people are likely to
> fall in.

Good. That's exactly what it was supposed to do to your mind. Now you need to
learn to live with this awareness, and you need to learn how to minimize the
amount of traps you leave behind.

> I also find C# code very ugly compared to both Python and Haskell. On the
> visual level, the mandatory use of braces everywhere [...] makes code
> contain a lot of line noise and empty space, and combined with the verbosity
> of the libraries and type declarations etc, you find that a page of C#
> hardly does anything.

Learn two or three more languages and you'll find that this visual clutter
hardly matters. What's important is how much can you do with the same amount
of statements and expressions (I find Paul Graham's proposition that this is
related to the count of AST nodes appealing).

> 2\. Using functional style obfuscates your code when using other languages.

This sounds like the really old programming joke: "good programmer can write
in Fortran in any language".

Some constructs are not a good fit for some languages. I avoid map(),
filter(), and reduce() in Python like the plague, but I find list
comprehensions appropriate. You need to learn to switch between paradigms and
sets of idioms, not to cram the same set everywhere.

~~~
douche
> > I also find C# code very ugly compared to both Python and Haskell. On the
> visual level, the mandatory use of braces everywhere [...] makes code
> contain a lot of line noise and empty space, and combined with the verbosity
> of the libraries and type declarations etc, you find that a page of C#
> hardly does anything. > Learn two or three more languages and you'll find
> that this visual clutter hardly matters. What's important is how much can
> you do with the same amount of statements and expressions (I find Paul
> Graham's proposition that this is related to the count of AST nodes
> appealing).

I would agree that if you follow the official Microsoft C# style conventions,
you end up with some ugly looking, noisy code. I am not a fan of sticking
opening braces on their own line, or forcing a newline between closing braces
and else, catch, finally keywords. It is just a waste of too much vertical
space, for questionable benefit.

------
contravariant
By now you can do better in c#. You can do the following, for instance:

    
    
        mylist.Select(item => item.description)
              .Where(descr => descr != "")
              .Aggregate(a,b => a + "\n" +  b)
    

Edit: I guess those features weren't available at the time of this article?
Haven't used c# for long enough to be sure.

~~~
kidmenot
Correct, in 2006 there were no LINQ, extension methods and a number of other
great improvements which kind of makes the article less valuable.

Not that it was terribly valuable to begin with: as a programmer, using the
language at hand to write code that 1) works and 2) is as clear as possible is
exactly your job.

Emulating other languages because of feature envy is really stupid, the first
C# snippet is a prime example of this. I would not want to work with someone
who deliberately makes the code harder to read in order to mimic his/her own
favorite language. Every language has its idioms, just learn them and quit
bitching.

As a side note, the example chosen was particularly poor because, if the
collection contains a huge number of items, concatenating them without a
StringBuilder in .NET land is a terribile idea.

------
maze-le
I don't know how it is with you, but I think I have learned a lot by learning
Haskell - and I think it has made me a better programmer. I have to say, I am
in no way fluent in Haskell (anymore), and I prefer erlang as the functional
PL of my choice (better libraries, more open community).

I had a series of courses about concurrent programming at the University, with
a Focus on programming in Haskell. Learning Haskell has taught me 2 things,
and I am immenseley gratful that it did:

* The power of abstractions

* The power of types.

The second point is absoluteley incredible in Haskell. With proper reasoning
about your datatypes, the implementation almost becomes an afterthought. I
never had that insight when I was using Java, C or another statically typed
language.

Also: I think if this aricle would be written today, the authour wouldn't be
so frustrated. Many functional concepts have influenced other languages in the
last 10 years (especially C#).

~~~
SAI_Peregrinus
Haskell may not be the best in production, but it's amazing for learning
computer science. It's also pretty good for learning quite a bit of
intermediate and advanced programming. The concepts and styles of thinking it
teaches can be applied elsewhere to great effect.

------
lostcolony
It's like why becoming fluent in a second speaking language makes you a
'worse' speaker in your native tongue. You sometimes confuse idioms and terms,
and sometimes you find yourself frustrated when trying to find a word in one
language, when the perfect word exists in the other.

(Tongue-in-cheek, if not apparent)

------
progman
> Further, my experience with Haskell means that I now see potential bugs
> everywhere in imperative code. ... I am constantly aware that I am writing
> traps that other people are likely to fall in.

Did that not make him a _better_ programmer? Did he actually mean "Why
learning Haskell/Python makes you a worse _feeling_ programmer"?

------
agentultra
Think that's tough? Try learning formal methods and how to design software to
be correct by construction. Haskell would be an easy sell. But regardless of
language few seem capable of catching errors in logic -- the kind that lead to
race-conditions, starvation, dog-piling, cache misses, consistency errors,
etc.

The kinds of errors whose frequency and impact we are ill suited to estimate.
"Bah, that could only happen for 1 in 100k requests." Now your system is
serving 3M requests a second. It's very likely you'll be seeing that error.

Don't be discouraged though. You might read about a new distributed lock in an
important open source cloud orchestration framework that the public is
building service infrastructure on and not find a single executable
specification. Doesn't mean you can't write one and submit a pull request when
you inevitably find errors in it. You just have to keep such alien super
powers under wraps.

Similarly if your goal is to write more Haskell at your job: just find
opportunities to use it. Preferably ones where you can keep the secret of the
sausage to yourself. When your bosses and colleagues begin to wonder how you
consistently kick butt you can tell them. Then they might want to learn too.

At least that's the story I tell myself. Most people are happy in their own
instance on Plato's cave. If you bring in new ideas you might be ousted from
the group. Or fired.

Just keep doing the best mediocre job you can and try not to think about it
too hard!

------
bad_user
Haskell and Python are two languages that couldn't be more different. Are
there developers that prefer both and constantly switch between them? Besides
the obvious that Python has one or two cool libraries, why would anybody
willingly do that?

~~~
rprospero
Hello, I'm that guy who voluntarily writes a mixture of Python and Haskell in
his day job.

For me, it's about recognizing the strengths in both languages. You mentioned
Python having "one or two cool libraries", but that's quite an understatement
if you're doing any sort of numerical work. NumPy and SciPy are incredibly
powerful, fast, and consistent. While hMatrix and Accelerate are both
wonderful packages and have made some great progress, they don't have nearly
the community support that Numpy does.

On the reverse side, when I'm dealing with any sort of interactive system
(e.g. Web Scraper or Motor Controller), I immediately reach for Haskell, since
it makes those kinds of applications so much easier.

For me it's mostly about just finding the right tool for the job. And trying
to avoid any job where the right tool is Fortran.

~~~
exDM69
> On the reverse side, when I'm dealing with any sort of interactive system
> (e.g. Web Scraper or Motor Controller), I immediately reach for Haskell,
> since it makes those kinds of applications so much easier.

I find this a bit surprising... can you tell a bit more about these projects?

I tend to do the opposite, I reach for Python when I need interactive stuff or
need to interface with the "real world" more (network connections, etc). And I
use Haskell when I have projects that have well defined inputs and outputs.

------
UK-AL
The comparisons with c# in this article is 10 years out date, so they are no
longer relevant.

------
lawlessone
I finally have an excuse.

------
iofj
I do actually experience this : functional style is shorter, more effective,
and more bugfree, and you can do it even in Go (if you're willing to copy bits
to compensate for lack of generics).

However, there is a large class of programmers that will kill you on the code
review if they see this. Mostly I think it's for lack of understanding, or
I've gotten comments complaining exactly that it's not imperative code.

Unless you're willing to educate your colleagues, the post may have a point :
learning functional style will improve your programs but seriously increase
your frustrations.

~~~
elcapitan
The post sounds like an instance of solving the wrong problem. If you can
write more concise, elegant and bug-free code, but all your colleagues can't
deal with it and want to stick with their stuff, you're probably in the wrong
place.

On the other hand: Python doesn't exactly impress me as a particularly
"functional" language. The examples are not as straightforward as the Haskell
examples. Python uses a weird mix of OOP, imperative and functional
programming, and this creates mental strain for everybody who has to read it.
When I switch from Ruby to Python, I usually enjoy the simple imperative-
pseudo-code like way of how the most idiomatic code there works. Then when I
go back to Ruby I'm happy to use idiomatic metaprogramming, chained blocks of
code etc.

The same is true for Go and probably part of the current fascination of the
dev community with the language (because it's proud of constraining complexity
of expression).

~~~
accountt
> Python uses a weird mix of OOP, imperative and functional programming, and
> this creates mental strain for everybody who has to read it.

I used to think so until I came across Oz. It's Prolog, Lisp and Python all in
one nice package :) Granted, it's more of an educational language, still
though, Oz is a mind-stretcher.

------
draw_down
Well, "writing traps that other people are likely to fall in" does sound bad.
I'm not sure I understand why that would be made excusable due to... knowing a
couple other languages and that they exist?

