

Why Learning Haskell/Python Makes You a Worse Programmer - antiform
http://lukeplant.me.uk/blog.php?id=1107301645

======
brentb
The author's C# example predated the release of LINQ, which makes the C#
syntax much more like the Python's. The author's code:

string.Join("\n", mylist.ConvertAll<string>( delegate(Foo foo) { return
foo.Description(); }).FindAll( delegate(string x) { return x != "";
}).ToArray());

can be rewritten as:

string.Join("\n", (from f in myList where f.Description() != "" select
f.Description()).ToArray());

which is super-easy to read and understand. Maybe not as concise or pretty as
Python or Haskell, but definitely a step in the right direction.

Others' comments that the author should consider F# are well founded, as it
integrates seamlessly with other .NET-based code (such as C#) and is a pretty
great language. However, it's worth noting that the post was written in 2006,
well before F# was widely known about or distributed.

~~~
d0mine
Perl:

    
    
       join "\n", grep { $_ } map { $_->description } @myList;

Or

    
    
       join "\n", grep /./, map { $_->description } @myList;

Ruby:

    
    
       myList.collect { |f| f.description }.select { |d| d != "" }.join("\n")
    

Python:

    
    
       descriptions = (f.description() for f in mylist)

Or if we'd like to constrain ourselves to one method `FooClass.description()`

    
    
       descriptions = map(FooClass.description, mylist) # `map` returns an iterator in py3k
    
       "\n".join(filter(None, descriptions))   # `None` means `lambda x: x` here

Or if you don't like `filter()`

    
    
       "\n".join(d for d in descriptions if d) 

Or if `description()` is a side-effect-free method then It should be a
property:

    
    
       "\n".join(f.description for f in mylist if f.description)
    

At the end of the day new features doesn't matter due to most .NET-shops use
old C# versions and It will not change any time soon.

~~~
bprater
Which seems the most "readable"? I think the Ruby one might be.

~~~
lsb
Using Symbol#to_proc, the old Ruby

    
    
      myList.collect { |f| f.description }.select { |d| d != "" }.join("\n")
    

becomes

    
    
      myList.map(&:description).reject(&:empty?).join("\n")
    

which is even more direct: take my list, map each element to its description,
reject anything empty, and join with newlines.

~~~
d0mine
I thought `Symbol#to_proc` is a Rails' extension.

~~~
lsb
I learned about it in 2005, when I read it on
[http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc....](http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html)
and it's such a good idea that they've folded it into 1.9
<http://www.infoq.com/news/2008/02/to_proc-currying-ruby19>

------
silentbicycle
"The fact is that functional idioms work badly in languages that don't have
syntactic support for them."

Then _don't use those idioms_. Work _with_ your language, not against it.
Learning Haskell taught the author to be more conscientious with state. Good.
But nobody wants to debug imperative/OO code written by somebody newly
infatuated with Haskell* -- it's like when people study a foreign language in
high school and start dropping little fragments of
Spanish/French/Japanese/etc. into casual conversation all the time, oblivious
to whether the people around them understand it.

One of the comments (by "tom") nails it:

 _One of the more potent reasons for learning other modus operandi in
programming to keep you from building tolerance to the same assumptions._

Learning several unrelated languages will almost certainly make you a better
programmer, but code that assumes everybody else you're working with has the
same background as you will be difficult to maintain. The language you're
working in is the foundation for your shared culture, so do your best to write
idiomatically in that.

* I have been guilty of this.

~~~
sethg
Agreed. I think the point of learning multiple paradigms is so that you can
recognize when idiomatic programming in your preferred (or employer-mandated)
language is _not_ the best way to get the job done--recognizing when it's time
to write functional-style code in Python, OO-style code in Haskell, or
whatever. But most of the time, you follow the grain of the language.

~~~
silentbicycle
Absolutely. Some languages comfortably support several paradigms, of course
(<http://www.c2.com/cgi/wiki?MultiParadigmProgrammingLanguage>).

~~~
sethg
I think any non-toy language needs to make it _non-painful_ to program in
several paradigms, but I'm not sure about the "comfortably" part; it's good
for a langauge to be designed around a central paradigm that can work for most
tasks and that the implementor can optimize for. So Python is OO and Haskell
is functional, and there are many problems that you solve in an OO style when
writing Python and a functional style when using Haskell, and that's OK. And
every once in a while you need to write functional-style code in Python, or
OO-style code in Haskell, and that's OK too. I'm OK, you're OK, we're all
OK....

------
nirmal
_Update: I probably should have made it more obvious for some people that the
title of the post is not entirely serious, and mainly I'm just griping._

I think this explains the whole article and why there is no serious discussion
here.

------
chwolfe
Comparing C# 2.0's functional capabilities to Haskell/Python is terribly
misleading. You can perform functional tasks easily in 3.5 using lambda
expressions and built in functional operators such as:

listOfTestObjects.ForEach(x => sOutputDescriptions += "\n" + x.Description());

[http://weblogs.asp.net/scottgu/archive/2007/04/08/new-
orcas-...](http://weblogs.asp.net/scottgu/archive/2007/04/08/new-orcas-
language-feature-lambda-expressions.aspx)

~~~
brentb
I hate to nitpick, but this isn't comparable to the author's code. You're
including empty descriptions and your output string will begin with a newline.
These seem like small details, but they make a big difference in the
conciseness with which you can write the statement.

~~~
chwolfe
This is very true. I was not attempting to port the author's code to .NET 3.5
as much as to introduce C# lambda expression syntax to the readers here.

~~~
brentb
Yeah, I figured. I just didn't want others coming away with the impression
that C# is _more_ concise than Haskell or Python. I mean, I love lambdas as
much as the next C# programmer, but there is still a fair bit of clunky syntax
to deal with when using C#'s great new features.

------
russell
The obvious answer is to switch to Brainfuck, the any at-work language, even
Cobol, will be a pleasure to work in.

------
RiderOfGiraffes
Actually, there are some serious points here. Consider this:

[http://www.postmodernprogramming.org/stories/fixed_point_mad...](http://www.postmodernprogramming.org/stories/fixed_point_madness)

------
jganetsk
The title is "Why X makes you a worse progarmmer"

Then his conclusion: "I have no doubt that in general I am a better programmer
for learning these languages..."

Um, hello?

~~~
whatusername
Update: I probably should have made it more obvious for some people that the
title of the post is not entirely serious, and mainly I'm just griping.

~~~
jganetsk
Or you could have titled it "Why using X makes me a worse software engineer"
seeing as that's your conclusion.

------
divia
...when programming in less powerful languages, because they start to seem
inadequate.

 _I constantly find myself wanting to use idioms from these languages, or
noticing how much less code I'd be able to write if I was using one of these
languages._

------
DaniFong
C# was, to me, the best available language in TopCoder competitions. Once I
had more than a passing acquaintance with Python, Lisp, Ruby and Haskell, it
was annoying to compete in it. I spent a bunch of time trying to imagine a way
to write in a language of my choice using code generation. Eventually I just
gave up, and stopped playing (though this was one of many contributing
factors)

~~~
cgranade
C# feels dreadfully underdesigned to me. Despite its massive flaws, I still
love Java for how consistent it is, and for how well-thought out it is. For
instance, generics in C# aren't getting covariance and contravariance until
4.0, which I consider to be a fatal flaw. "List<? extends String>" makes so
much more sense than "List<out T> where T : string".

That said, I am sad that the BGGA closures proposal won't make the cut for
Java 7. I hope that some IDEs and APIs support it anyway.

~~~
DaniFong
I tended to use fairly flat data structures in my own code, so the extra
hassle with generics didn't often come up. I did, however, use delegates
(closures!) all over the place. They're verbose, but I mapped the delegate
definitions to a resharper macro and it only took two keystrokes. That helped
while writing code. It still was a pain to read, though, and ultimately the
macro language wasn't good enough to do what I wanted.

The thing I like about Fortress is that it's a grown and growable language,
with almost all constructs first class and exposed. Just like Lisp. But it's
coming from the complete opposite direction in terms of syntax. Lisp barely
has any syntax. Fortress gives you the most powerful production parser in a
programming language, plus extremely adaptable syntax (where _spaces_ can be
operators!) plus a wicked way to render code, plus the ability to make your
programs platform portable, adaptable, and parallelizable. It can be looked at
as a programming language, true. But it can also be fruitfully imagined as a
powerful framework for building one's own programming language. This is what I
like to do with it. :-)

------
thomasmallen
Enthusiasts always put their language of choice on a pedestal. Python is a
very good language, but I often find it to be too restrictive and will use
Ruby/Perl for elegant metaprogramming and Erlang for functional programming.

~~~
silentbicycle
You completely missed the point of the article. It isn't about why Python &
Haskell are good or bad languages, it's about how learning them doesn't
necessarily improve ones' ability to work on projects _with other developers,
in unrelated languages_.

There are social factors in language choice, it isn't just about the quality
of the language itself.

~~~
thomasmallen
And my point is that every language is flawed. If you only focus on the unique
features of the languages you learn, you may not become a better program when
working with languages that lack these features. But simply assimilating these
ideas will do quite a bit to improve your productivity as well as your wisdom
when designing systems because you will be alert for inadequacies that you
would have missed before.

~~~
silentbicycle
I agree with you.

~~~
thomasmallen
And I wish I had a silent bicycle...

------
zmimon
As others have said, stop fighting the language and embrace it. For the Java
haters, here's a Java one-liner that is not much longer (though I'll admit,
uglier) than all the rest:

result = join(new ArrayList<String>(){{ addAll(list); while(remove(""));
}},"\n");

And as a bonus - for the extra few characters you typed, this will fail at
compile time instead of runtime when the list turns out to contain FooBars
instead of strings.

~~~
cgranade
Missing the application of Foo.description(). That said, I feel that compile-
time failure is vastly underrated. Java is making even more progress on that
front by introducing type checker frameworks with JSR 308.

------
gaius
So why not use IronPython or F#?

~~~
prospero
This article is two years old, at which point F# wasn't much more than a
research project.

------
shadytrees
That's an extremely rash claim: I'm struggling to adapt to a different
language, and so will you.

~~~
silentbicycle
That's not what the article says.

------
ryanwaggoner
Alternate title: Another article demonstrating that trolling works.

------
villageidiot
The title is catchy but imprecise. After discovering the concision of python
and haskell, the author has less tolerance for the verbosity of c#, the
language with which he earns his living. Perhaps the solution is to earn a
living with a more concise language.

~~~
nirmal
_The moral of the story: don't bother improving yourself, unless you have the
freedom to improve your environment accordingly._

That's the moral of the story? That's not a moral, that's whining.

~~~
qqq
Don't improve? Seems _immoral_.

------
time_management
Reminds me of a time I screwed up a Java project (well, not really; just took
a long time to write code most Java devs wouldn't understand) by using
attempting to use generics and Java's static typing system to build-up an ML-
esque ADT system.

4-ply parameterized types (e.g. string array list option) do not attractive
siblings in Java-land.

