All Unkept
Posted in: Haskell, Python, Rants, Software development  —  30 August 2006

Why learning Haskell/Python makes you a worse programmer

I've found, contrary to what you sometimes read, that learning Python and Haskell has not improved my programming using other languages. Haskell in particular, being so different from imperative languages, is supposed to give new insights into programming that will help you even when you are not using the language. My current experience doesn't exactly tally with this, and here is why:

  1. Demotivation.

    I find I think in Python, and even in Haskell to some extent, even though I have used Haskell very little. 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 (which, although very different from each other, are both much more powerful than the language I use at work, C#). It's very common for me to notice that using either of these languages I could decrease a chunk of code by a factor of 2-5, and not rare to see a factor of 10-20 in certain parts of the code base.

    Further, my experience with Haskell means that I now see potential bugs everywhere in imperative code. Before, I was fairly well aware of the problems that stateful programming and side-effects can cause, having dealt with many scores of bugs related directly to this, and spent countless hours debugging these problems. But without any alternative, I guess I had just lived with it. 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.

    I also find C# code very ugly compared to both Python and Haskell. On the visual level, the mandatory use of braces everywhere (OK, they're not mandatory everywhere but are enforced by coding standards with good reason) 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. I'm also thinking of beauty on the mathematical level, C# is a grubby mud hut compared to the breathtaking, elegant tower that is Haskell.

    The net result of these things is to make me very depressed and demoralised. I feel like a human compiler, translating the Haskell or Python in my head into a language which is a whole level lower.

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

    C# has begun to get some features that are more friendly to functional style programming. So, the other day, when faced with a very common situation I tried a functional solution. I have a list of Foo objects, each having a Description() method that returns a string. I need to concatenate all the non-empty descriptions, inserting newlines between them.

    The code I wanted to write was this Python code:

    "\n".join(foo.description() for foo in mylist
                             if foo.description() != "")
    

    Or this Haskell:

    concat $ List.intersperse "\n" $ filter (/= "") $ map description mylist
    

    Using generics from C# 2.0 and the methods they contain, the best I got was:

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

    If I had been starting with a different data structure, the C# version would have been even worse -- and C# seems to have hundreds of different collection classes, used inconsistently in the .NET libraries. Also I should point out that if you write any methods that accept 'delegates' (the nearest thing to first class functions) you have to declare the function signature for them separately if one doesn't exist already (or if you don't know where to find one that already exists), further adding to the bloat of any functional style code.

    There are some big problems with the C# version. The first is that there is very little reduction in size versus the imperative style code, if any. Compare to the tedious loop I would have written otherwise:

    string retval = "";
    foreach (Foo foo in mylist)
    {
        string desc = foo.description();
        if (desc != "")
        {
                if (retval != "")
                   retval += "\n";
                retval += desc;
        }
    }
    

    There isn't much in it.

    Second, it took me longer to write. I had to do some experimenting to see how much type information I had to add to get it to compile (e.g. adding an explicit cast for the delegate turned out not to be necessary, but I did have to specify ConvertAll<string> instead of ConvertAll).

    Finally, there is the problem that this code will get me into trouble with my colleagues. Why am I writing such complex code -- using such advanced features as anonymous delegates -- when a simple loop would have sufficed? I actually left my functional version in, but was so embarrassed about it I had to add a brief explanatory note.

    The fact is that functional idioms work badly in languages that don't have syntactic support for them. Java, from what I know, would have been much worse. C# suffers in that although some features that enable more functional programming have arrived in C# 2.0 (along with various other language improvements), huge chunks of .NET libraries have not been updated to take advantage of them, and our own code certainly hasn't.

    It might be argued that you can still use the principles of functional programming (no side effects, functions depend only on their inputs etc) and get benefits that way, even if you can't use the idioms. In reality, libraries and frameworks designed for imperative languages just don't work like that. ASP.NET is an especially bad example. You develop controls by inheriting from Control and then overriding various methods. Most of these methods have no return value and no inputs, and work solely by mutating the state of the object (or other objects). They are then called by the framework in a somewhat subtle and complex order (yes, it is a nightmare to debug).

    In fact, applying the principles of functional programming would lead me to use only static methods (no instance methods) as much as possible, avoiding anything that mutates states (or even has the possibility of mutating state). I would use a few ubiquitous, 'dumb' datatypes, and keep algorithms separate from them. This flies in the face of the teachings, or at least the practices, of the main programming paradigm popular today, OOP. I can't apply what I think are good principles for writing code without rejecting the very paradigm of the language and libraries I am surrounded with. It's fairly hopeless.

So, learning Python and Haskell has demoralised me and encouraged me to write code that is bizarre and difficult to understand, and, in the context of an OOP code base, provides little benefit over imperative programming. I have no doubt that in general I am a better programmer for learning these languages, but in my current situation, I am not a better software developer -- my productivity has in fact nose-dived. When I get frustrated with the C# code I write, I then go and write it again in Haskell and Python, to demonstrate to myself how much better they are, which is a pointless exercise that only demotivates me further.

The moral of the story: don't bother improving yourself, unless you have the freedom to improve your environment accordingly. That's rather depressing. Can anyone put a better spin on this and cheer me up?

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.

Comments §

§ On 30 August 2006, Neil Mitchell wrote: 93
At least you don't have to use C?

The demotivation stuff is unfortunate, but perhaps you can change something in your code somehow. Maybe write a helper script in Python/Haskell and slowly introduce it into the developer environment. Auto generate some of your code, with Haskell functions in some way.

Or of course use Yhc, and produce .NET bytecode files from Haskell, which you then combine in with your C#.

As for the second point, the important thing is about getting the balance between functional style and functional thought. Try and eliminate some global variables where possible - Haskell makes you think really really hard before you introduce a global variable - which is a good thing!

§ On 31 August 2006, Andre Pang wrote: 94
Sure, a functional programming style in languages that provide little syntactic and semantic support for it isn't hard. Use the standard idioms of whatever programming language you're tied to: if you're writing in C#, use a loop like you mentioned, don't use anonymous functions. In professional software development, what you want is code maintainability above all else, and standard idioms means more maintainable code.

That doesn't mean you can't use anything from the functional programming world, though. My C++ code is now heavily littered with const qualifiers everywhere ("assign-once" variables), which you can also do in C# and Java, and I use STL algorithms instead of loops where I can.

§ On 31 August 2006, luke wrote: 95
Thanks for the suggestions! I hadn't thought about using Haskell for some scripting, which is the most likely way I'm going to get to use it (I have used Python in the past for this).

And yes, I'm glad I don't have to use C :-)

§ On 31 August 2006, Rene de Visser wrote: 96
Don't try to program in Haskell in another language. What you learn in Haskell can however help you in the high level design of your programs. You can model you programs using Haskells type system and idioms on paper. The detailed design and development will then use the idioms of C#. This can lead to programs with a cleaner overall design.

§ On 31 August 2006, wx wrote: 97
What you need, you need to write a function that will retrieve non-empty description strings from your list of Foo objects... like this:

string.join( "\n", get_descriptions(your_list ) )

List<string> get_descriptions( your_list )
{
List<string> result;
foreach(Foo foo in your_list)
  if(foo.description()!="") result.add(foo.description())

return result;
}

§ On 31 August 2006, George Jempty wrote: 98
Doesn't Jython cheer you up?

§ On 31 August 2006, luke wrote: 99
@George: It would, if I was 1) using Java and 2) was allowed to use it :-). The relevant equivalent would be IronPython, which I know I wouldn't be allowed to use.

Many companies would be very scared of having multi-lingual code bases for a single project -- out of the 30 or so programmers at work, I'm the only one I know of who uses Python, and I know of one Perl programmer. But the very existence of these two does cheer me up a bit, as they are likely to become mainstream enough to become acceptable.

§ On 31 August 2006, Bill Mill wrote: 100
Luke,

I'm generally a pythonista (and just started with haskell, of course) who just got a job writing c#. It's a step forward from VB5, first of all.

Secondly, I installed Trac at my job as soon as I got there, and it's spread like wildfire. I think of it as my Python trojan horse, and when I get pissed at writing another property that takes 7 lines instead of two, I can go hack on that to calm me down. (Beautiful code base, btw, highly recommended.)

Now if I could just convince them to dump SourceSafe...

§ On 31 August 2006, Joshua Volz wrote: 101
While I am more often playing in Ruby than in Python (I am also learning Haskell on the side when I am not doing 1 of 10 ongoing projects), I completely understand where you are coming from. Once you do something in a language that lets you do it fast, and with better paradigms, you can't go back. It almost hurts you to go back. [side note: did I just sound like a Lisp programmer?]

I do think IronPython is your savior in the future, but might not help you in your current position. Maybe the choice of language is one of the major benefits of working for yourself?

Bill Mill: get them to try SourceGear's Vault (http://sourcegear.com/). It has an excellent conversion program from VSS. It is also reasonably priced and allows you to access it via an IP address (which if you make available on the net means you can get to it from home). I had good success selling it to the managers at my last project, and good success using it there.

I think we are going to start seeing small companies using more productive languages (Python, Ruby, Lisp, Haskell,...) taking the business from larger more established companies using safer languages (Java, C#, ...). Smaller companies have the advantage of being able to move faster (less inertia), and they can put together a team that has a higher average ability easier, simply because the team is smaller. I can only hope that soon enough there will lots of jobs looking for people who know Python, Ruby, Haskell and their ilk.

§ On 31 August 2006, Lawrence Oluyede wrote: 102
You should seriously consider the chance to take a Python job :-)

§ On 31 August 2006, Dennis wrote: 103
I'm right behind you, except more on Lisp at the moment. Anyway...

1) IronPython is an official Microsoft language now, so you could probably make a case for it at a lot of places. (And Mono-based projects are starting to use a lot of Boo.)

2) C# 3.0 will have type inference, which oughta help a lot.

3) Or you could do what I'm starting to do...spend your time writing code generators instead of code. Use whatever language for your code generator you want, and just present the output to your colleagues. After a while they'll be amazed at your productivity.

The reason I'm getting into Lisp is that it seems that the macro system makes it the ideal language for writing code generators. The best option might be SLIME...it took some googling to find a way to connect it to sql-server, but it looks doable. There are also several opensource .net lisps, which is a nice option since all the .net libraries are available. However, none were quite what I wanted, so right now though I'm writing my own lisp interpreter in VB, during spare moments. It's not as hard as I used to think.




§ On 31 August 2006, Apoch wrote: 104
Having been a Smug Lisp Weenie for a while now, I totally sympathize. The important thing is to design functionally, and code to the idioms of whatever language you're stuck in. The other C++ guys on the team still look at my code like it's got legs, but at least they can understand what it's doing and why.

The other thing is to become an instrument of change. Push hard for new language policy, even training if you can. If you can spare a couple hours here and there, start converting particularly troublesome bits of the codebase on the side, just to demonstrate the potential benefits. Offer to help educate the other coders in-house. If your management has any sense at all, they'll at least *try* to work with you on it. It's worth a shot.

§ On 31 August 2006, Chris wrote: 105
> The other C++ guys on the team still look at my code like it's got legs<

This is a recipe for disaster. The 'other C++ guys' are going to knife you in the back when the opportunity comes, because you're making their lives more difficult.

> The other thing is to become an instrument of change <

This part I agree with.

§ On 31 August 2006, Chris wrote: 106
Luke: just imagine how much worse it could be: if you were a Ruby programmer, you'd bristle at the obscene amounts of code required to perform basic tasks in Python.

§ On 31 August 2006, jacob wrote: 107
> (Beautiful code base, btw, highly recommended.)

Bill: I find the Trac source almost completely incomprehensible at a high level, even though every individual method and class has very readable code. There's no high-level overview document i can find, the naming of classes is meaningless to me, and every module imports lots of stuff from other modules that isn't clearly explained.

I think that Trac code is way overengineered and overgeneralized, and does lots of unnecessary stuff. A bug tracker isn't such a huge problem space that it needs such code overhead.

§ On 31 August 2006, tom wrote: 108
i think you miss the point.

if you are thinking in any language while writing in another, then you will _always_ suffer. you want to think in the language you are working in!

the point is to learn programming, not programming in C#/LISP/Haskell/Python/etc. same with OS's, you learn computers, not windows or linux.

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

§ On 31 August 2006, Andrew Norris wrote: 109
I'm going through the same thing as I learn Lisp and Ruby and try to figure out what I can bring back to C#.

When C# gets the simplified syntax for anonymous functions (3.5, I think), your idiom should reduce to this:

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

which is a little better.

One of my main pet peeves is that I can't write defproperty(Foo, _foo, int) and other macros that get rid of a lot of useless boilerplate.

I have found some approaches to code design that I can translate back to more effective C#, but they mostly apply to architectural issues such as patterns for delegating code amongst classes. On a line-by-line basis, I try to stick to idiomatic C# just out of common courtesy to the rest of the team.

§ On 31 August 2006, Dennis wrote: 110
"One of my main pet peeves is that I can't write...macros that get rid of a lot of useless boilerplate."

Which is why I want to write Lisp programs to generate my C# :) ...and why a lot of .Net programmers are using other codegen tools like CodeSmith...but I think Lisp will beat any such tools easily.

§ On 31 August 2006, tom wrote: 111
i think you miss the point.

if you are thinking in any language while writing in another, then you will _always_ suffer. you want to think in the language you are working in!

the point is to learn programming, not programming in C#/LISP/Haskell/Python/etc. same with OS's, you learn computers, not windows or linux.

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

§ On 31 August 2006, Lionel Barret wrote: 112
Want to join our team ?
I am only half-kidding...

Having been in your place, I understand quite well the frustration.
my advice : Do bet too much on the company ability to change and follow the lisp suggestion above.

§ On 31 August 2006, Anonymous Coward wrote: 113
Yeah, that post with the comparison does a good job of showing how similar the two languages are and that you're probably not going to find something that one can do which the other can't.

So, yes, the "cute string" example is definitely possible in Python.

§ On 1 September 2006, tottinger wrote: 114
The python examples are for pre-list comp python, too.

I like the ruby/small talk "internal" iteration protocol better than the pythonh "external iterator" one, but both are mighty nice.

I did a few years in pure python on linux, and then had to transition to C# on Windows for a while, and now Java and C++ on windows... I miss python.

Well, I guess the answer is to be a good soldier by day (but do TDD and pairing and refactoring) and then do python or haskell or ruby to resurrect your soul.

§ On 1 September 2006, Sean wrote: 115
I feel for you, Luke. Though I don't think learning Haskell has made me a "worse" programmer, I do think it has made me yearn for a different approach to developing the software I have developed.

Since starting my first full-time job in May, besides doing hardware design, I was developing in C. And, while I don't agree with Neil Mitchell that C is so bad, it does rather cripple you by the fact that you have to develop alot of boilerplate. And I just want to high-level composition of functional calls! ;)

But here, the priority is, as usual, maintainability. Plus, we're working on an embedded system, for which no Haskell compiler exists. :(

§ On 1 September 2006, Andrew Norris wrote: 116
Dennis,

That's tempting. My main problem with most code generators is that, as with Lisp, I want the macro call to *be* the source code -- when I maintain the code later, I want that one line of code to be all there is.

Of course (and this may be what you're doing), you could use C#-generating Lisp in a way that makes the Lisp code your true source, but this makes for a complicated toolchain, especially since your debugger can't run against the code you wrote -- only the code you generated.

One thing I've been working with lately in my spare time is L#, an interpreted Lisp dialect for .Net. I'm intrigued at the idea of combining the power of the Lisp language with the power of the .Net libraries and infrastructure, though there certainly are still some missing steps in the toolchain there, as well.

§ On 2 September 2006, David wrote: 118
OK, nobody else has, so I'll dive in from the "sort of not the point" board. A better version of the loop is:

StringBuilder result = new StringBuilder ();
StringWriter writer = new StringWriter(result, CultureInfo.InvariantCulture);
foreach (Foo foo in myList)
  {
  string desc = foo.description();
  if (desc.Length > 0)
    writer.WriteLine(desc);
  }

// Remove final extra terminator.
return (result.Length > 0 ? result.ToString (0, result.Length - writer.NewLine.Length) : String.Empty);

Saves a couple lines of code, uses the actual OS-specific newline character(s), and is better in performance and memory usage as the number of Foos in myList increases. It's also more flexible if you need to do something spiffy, like culture-sensitive string formatting, but that's sort of irrelevant to the task at hand.

I realize that a discussion of performance characteristics is somewhat out of place in a post about Haskell and Python ;), but given that most people in shops using C# are going to need to worry about some of this stuff, at least sometimes, I figured what the heck. Also, I've spent enough time rewriting C# code that is just plain hideous that I'd like to nip some of it in the bud, if there's any way at all to do so....

§ On 3 September 2006, Chris wrote: 120
In java I would do something like...

StringBuilder builder = new StringBuilder();
for (String word : list) {
   if (word != null) {
       builder.append((builder.length() == 0) ? word : "\n" + word);
   }
}
return builder.toString();

...which doesn't seem so bad. Tucked into a utility class it would serve the purpose in terms of reuse as a language construct.


§ On 3 September 2006, Anonymous Coward wrote: 121
"out of place in a post about Haskell and.."
Haskell is Faster than Java (on average) - take a look at the grate programming language shootout - although for plain algorithms involving integers, arrays, loops etc. Java can be as fast as C is

§ On 3 September 2006, David wrote: 122
Well, I was talking about C#, not Java, but my main point was that I've never heard of anyone mentioning using Haskell or Python in the context of looking for better runtime performance. (Based on the results of the GPLS, it seems it won't be for some time to come, either.)

§ On 3 September 2006, barry.b wrote: 123
If I were your manager (and thankfully for both of us I'm not) I'd consider locking you out of the building.

where's the organisational standard to uphold - for better or worse? is this a C# dev house or a Hascal/Yhc one?

or is it a case to shoe-horn any solution at a whim and heaven help the poor sod comming along later who has no idea what your code means?

please accept this in the lighthearted manner it was writen but IMHO you gotta love using your tools (language) - warts 'n' all. otherwise it's a chore.

It's like marrage: take the good with the bad and get along with life ... or get a divorce and try something else....

eh, my 2c (going thru a similar gripe myself... and using your post for a bit of "therapy" - please forgive me)

§ On 5 September 2006, Julian Morrison wrote: 124
What I recommend is that you actually do learn to think like a compiler. See the hidden terms. Most C# and Java calls will have a hidden "self" reference, many will pass through a hidden state monad. Think in terms of meaning-preserving transformations. Mapping rotates into iteration. Composition becomes "final local" variable assignment and usage. You can produce clean, idiomatic code that way, using your mental Haskell to reduce the scope for bugs.

§ On 30 September 2006, novitk wrote: 137
I'm programming in the mix of C++,Java and C# and know exactly what you are tlking about. While decent languages no doubt, once you've seen the light of Python, Haskell, Smalltalk, Lisp you'd feel handicapped by them not unlike when developing in VBA or some other monster.

Anyways on a positive note have you heard about Nemerle (www.nemerle.org)? In short it's a functional, staticaly- typed, compiled language with a mix of OCaml and Haskel idioms, running on .NET and Mono with a full interop. It's not pure like Haskell, but more of a Ocaml like mix. IMHO it's briliantly designed and has some things that may even make a Haskell fan jealous (for example, it supports Lisp-style macro metaprogramming).

§ On 2 October 2006, art wrote: 141
C# 3.0 (available in preview) adds functional programming features. See Confessions of a Used Programming Language Salesman
Getting the Masses Hooked on Haskell
 by Erik Meijer

§ On 3 October 2006, Ned Batchelder wrote: 142
Yearning for better tools and languages is nothing new. Even once you get your dream development environment, you'll wish it were better. Doing something about it is the challenge.

More at http://www.nedbatchelder.com/blog/200610.html#e20061002T202237

§ On 3 October 2006, Anonymous Coward wrote: 143
Here's the answer :)

http://www.python.org/community/jobs/

§ On 3 October 2006, JohnMc wrote: 144
Anonymous Coward,

Well that's an answer but maybe not the best one.

Luke,

Take some spare time (always in short supply) and do one of two things with it. Theme -- Be a human virus.

1) If what you are working on is a rather large application why not embed python in the applicaion? That's the bottom up approach. That way those peksy solutions wanting to get out can be a script in the tool.

2) It it's more of a utility program then top down is probably better. Use Python to provide an umbrella wrapper. Acting as glue, the underlying C# code can be used for those areas where it's needed most.

Caveat. You of course understand the dangers? Your prototype has to be at least 60% bullet proof and cause no harm to the underlying code base. Second you most likely need to be prepared to do a skip level introduction of your idea to management. My observation is that the line manager was most likely the one who selected the language and they picked it based on their comfort level. so you are going over their head in a sense to hopefully a more neutral third party. But there are risks.

But the reward, ah the reward, you get to use your skills. And is it worth it? Yep. A VP once told me -- "You spend 1/3 of your life working. Why waste that time in sloth and despair?"

§ On 3 October 2006, MichalT wrote: 145
PHP:

enum($mylist)->filter('$value[\'description\']')->join("\n");

It's all in the libraries you use. Although I do like the syntax of Python and Ruby.

§ On 4 October 2006, Anonymous Coward wrote: 146
What I hate the most about Python and Haskell and Ruby and Smalltalk is the way that they have no flaws at all. It's depressing having languages that are provable silver bullets, yet idiotic management refuses to acknowledge their natural superiority.

It is strange that there's so many languages that are all better than all other languages, though. Maybe we're living in some sort of klein bottle universe?


> Here's another way to do it, AND it's (dare I say it) readable.

You may say it, but if it can't be done in one line of code that's read from the middle to the back to the front then it's not worth doing.

§ On 4 October 2006, Leo wrote: 147
I wouldn't recommend using functional paradigms in an OO language. As you say, it means creating difficult and bizarre code. Remember, the guy after you will probably be hired for his OO skills, and he'll have a terrible time understanding your code. You may even end up at TDWTF.
Moreover, whining over tools you may not use is only an issue if you're coding for your personal satisfaction. Learn to understand that the project and its quality is the goal or your work, not satisfying your sense of "elegance". (I can hear the crowd gnashing their teeth!) Less code is not _always_ better, and string concatenation is not _always_ the task at hand, and functional languages are not _always_ easier and more elegant than OO languages, especially from a design and process perspective.
I'm still searching for the perfect language - but there probably never will be. Cheer up! Don't try to build a wooden house out of bricks. Use the tools you've got in a way that makes perfect sense to you - from there you can derive your satisfaction. Remember: Professionals don't cry ;-)

§ On 5 October 2006, Max Battcher wrote: 148
One of the great things about C#/CLR is that even if your management won't allow you to put Python in the main codebase, you can certainly use it for the myriad of other tasks... I love being able to open an IronPython console, load the DLLs for the large C# application and "walk around" the codebase dynamically. It's a great test environment because I make up wacky tests as they hit me. Also, with large data-driven applications it is nice to query the data in the same ways that my application code does rather than having to open up a seperate SQL or data analyzer.

There have also been several tools that I've been able to quickly prototype in Python, demo on my development box, and then once they've been approved rewriting "stronger" versions in C#.

§ On 18 October 2006, Anonymous Coward wrote: 155
The solution is to find a job programming in python (or similar languages such as ruby or perl). If you continue to program in C#, you will stay in anguish, and your development as a programmer will be slowed.

§ On 19 October 2006, Paddy3118 wrote: 156
I notice that rant Luke!

<python="sorted(str.split('cheek tongue in'), reverse=True)">
On a positive note, is their some self-contained part of your bosses task that you could ask to do in IronPython for a comparison. If yur boss OK's it then make sure you stay up nights! The Python needs to be more readable, better tested, better documented, and well integrated with the C# code. You then only have to do a perfect presentation to doubters before sitting back, glowing in the knowledge that you have given it your best shot.

To the commentator(s) that automatically think that scripting languages are slow: you maybe loosing out to competitors here. Although some *tests* do often show compiled language solutions running faster than their equivalent Python code, you may also have a larger code base/development team/maintenance heaadache/team management issues with the more verbose, less readable, slower to develop, less tested C#/Java/C++ (what else can I add ;-) , version.
Often, Python allows differing agorithms to be explored that can result in a much faster Python solution than an inferior - but more immediate algorithm coded in a language that doesn't give you the time to explore.

I've just looked at Mercurial:
http://video.l.google.com/videoplay?docid=-7724296011317502612
Written mainly in Python, it achieves its speed by close attention to its algorithms, and is decribed as being faster than, aand using less disk space than many of its competing tools written solely in a compiled language.

Oh, and one for the Ruby fan:
  http://en.wikipedia.org/wiki/Doctest
My scripting language is better than yours!
(It seems it is expected of us :-)

- Paddy.

§ On 9 November 2006, Wes wrote: 157
I feel your pain. Fortunately, we are doing some great work that will be out in C# 3.5. Here is what the solution will look like then:

        var result1 = mylist
                       .Where(x => x.Description != "")
                       .Select(x => x.Description)
                       .Aggregate((x, y) => x + "\n" + y);

        var result2 = "\n".Join(from x in mylist where x.Description != "" select x.Description);

        var result3 = mylist
                        .Where(x => x.Description != "")
                        .Select(x => x.Description)
                        .Intersperse("\n")
                        .Concat();

A few approaches to the problem.

Cheers,
Wes Dyer

§ On 9 November 2006, luke wrote: 158
@Wes: that sounds great!

One thing: from using Haskell, it seems to me that OO approaches to collections are very much inferior to functional ones, because with OO you either have to build in every possible method that people would like to use (which is impossible), or you have to create 'utility functions' that have second class status compared to the builtin methods.

In Haskell you always manipulate data using functions, so a function provided by a third party to work with a collection is used just like the functions provided by the collection author. Ruby gets around the problem by having all classes open, so you can add more methods. How do you handle this in C# 3.5 - e.g. if your collection class didn't have an 'Intersperse' method, but you wanted to use one?

§ On 1 December 2006, Wes Dyer wrote: 161
Good question Luke. I did omitted the details of how to extend a class's functionality without having access to it. C# 3.5 provides extension methods to do this. An extension method is a static method that takes the receiver of a method call and uses it as the first argument to the extension method. Here is the intersperse method:

static class Extensions
{
  public static IEnumerable<T> Intersperse<T>(this IEnumerable<T> sequence, T value)
  {
    bool first = true;
    foreach (var item in sequence)
    {
      if (first) first = false;
      else yield return value;
      yield return item;
    }
  }
}

Of course there are other possible definitions of intersperse but this one demonstrates the use of extension methods to extend all the IEnumerable<> interface with a new method called Intersperse. Note the "this" modifier on the first argument to Intersperse. Now if the static class Extensions is in scope and there are no member functions called intersperse on the receiver and the receiver implements IEnumerable<> then the call will executed. Note that this trivially is translated as:

  rec.ExtensionMethod(arg1,...,argN)

  ExtensionMethod(rec, arg1, ..., argN)

§ On 27 December 2006, Lisper wrote: 164
Wes Dyer wrote:
>var result2 = "\n".Join(from x in mylist where x.Description != "" select x.Description);

Oh, my God! They finally have implemented loop facility. Why not to implement defmacro, then rename C# to CL# ? ;-)

§ On 29 January 2007, Oleg Andreev wrote: 165
If the list is not very long, this Ruby func-style solution looks pretty good:

arr.dup.delete_if{|f|f.description == ""}.join "\n"

For performance reasons it could be rewritten to good-old loop. Or there could be an optional filtering lambda for join() method.

§ On 30 January 2007, Anonymous Coward wrote: 166
>Why I am writing such complex code --
>using such advanced features as
>anonymous delegates -- when a simple
>loop would have sufficed? I actually
>left my functional version in, but was
>so embarrassed about it I had to add a
>brief explanatory note.

Oh man, that had me LOL. I know the feeling. I felt like i was just being a nuisance and a show off when i started slipping generics into my C# code.

i ended up having to go through it with the other programmers in a big meeting to show that it's not the end of the world and actually means we can solve our problems faster.

thanks for a great read!

§ On 9 February 2007, Anonymous Coward wrote: 167
Your title is OK. Some people just don't get it !!!!! Why is it necessary to explain every joke or snide remark or sarcasm ?

§ On 21 February 2007, Alex Lebedev wrote: 168
Well, learning Haskell, Python or Ruby really makes you worse C# programmer the same way getting university degree makes you worse factory worker.

Go find another job where you can apply your skills.

§ On 9 March 2007, Jafar wrote: 169
Although I agree that C# 2.0 is pretty clunky and ugly, as Wes points out C# 3.5 looks just as much like Haskell as it does Java. In fact most of the list operators in Haskell are present. Not only that, you can convert code into data just like in LISP. For some examples of some truly kick ass C# 3.0-fu check out my blog at themechanicalbride.blogspot.com . Just download the CTP and you will see how beautiful your work language is about to become.

§ On 21 March 2007, Julian Ashworth wrote: 170
I was taught ML in the early 1990s and it's great to see a mainstream language like C# 3.0 finally get some funcy features. F# and SML.NET are also worth a look.

§ On 26 March 2007, Sebastian wrote: 171
I use C++ for my day job, so I feel your pain :-(

§ On 25 May 2007, Nathan wrote: 209
I saw the title in this post while googling something else, and I was at first pissed off that someone could say this.

Then I read the post.

And I agree. Totally. I'm a python/haskell lover who writes depressingly imperative and stateful C code most of the time.

Damn it.

§ On 30 May 2007, Oleg Anashkin wrote: 210
Try Nemerle - it has best of both worlds (functional and imperative). And it produces normal .NET assemblies, so you can interop with other .NET languages.

§ On 12 July 2007, Chad Smith wrote: 218
I can't believe the functional constructs coming in .net 3.5 have been mentioned, but linq hasn't.

I'm writing this without testing it (or actually having an environment to do so) so it's probably wrong, but hopefully close.

String.Join(from foo in mylist where foo.description != "" select foo.description, "\n");

To my eyes that's an elegant solution which mixes some OOP with some functional concepts. It's perhaps a little out of line to suggest as an alternative to many functional languages which are mature and in use today, but I have great faith in C# and particularly Anders Hejlsberg and believe C# will keep getting stronger in the area of taking functional ideas and making them work elegantly inside traditional OOP code.

§ On 12 July 2007, evan wrote: 219
I love the web. Today, I wanted to learn a little bit about Haskell (and ocaml), and a few hours into my googling, I am thoroughly convinced that the effort is worth it. Thanks, everyone.

§ On 29 July 2007, Rasmus wrote: 234
It takes time. :>

If you have a good 'teacher' to help you or have the motivation it is worth it.

§ On 9 October 2007, jpd wrote: 275
LINQ does indeed make the syntax for this much more elegant, and if you don't like the syntactic sugar you can always use the lambdas directly.

The following compiles and does what is expected in C# 3.5:

String.Join("\n",
   (from foo in fooList
    where foo.Description != ""
    select foo.Description).ToArray()
);

(The .ToArray() is necessary because String.Join only does String[], oddly enough)

C# 3.5 reduces many of these tedious longhand coding cases down to simpler code that clearly says what it does. Now, it's not ever going to be quite as succinct as Python or Haskell - different languages for different problems, and you're going to continue to be frustrated so long as you don't realize *why* C# is sometimes the better choice for a shop, despite (or perhaps because of) the brevity of expressing solutions in dynamic languages. But 3.5 is going to ease alot of our pains - and with any luck the DLR, IronPython and friends will soon have proper toolchain support, and we're going to have *alot* of interesting options opening up when that happens.

Of course, C# 3.5 is also going to create entirely new forms of Very Bad Code in the hands of green coders - I expect to see 'var x' unnecessarily littering codebases everywhere soon, and that's just the tip of the iceberg.

§ On 5 November 2007, Sunnan wrote: 281
I definitely agree about both of those two flaws; the obfuscation issue dissapparead after a while (just like when I first learned dvorak ten years ago, it slowed down my qwerty for a while) and now I do write better Java than I did before I went functional; just like I'm faster at both qwerty (as long as I don't have to use keyboard shortcuts - I learned Emacs about the same time I learned dvorak) and dvorak.

However, the saying was originally (if ESR's "hacker howto" is part of the origin) about lisp-like languages rather than functional languages, and I must say that writing in sexp languages does so much for how you think about syntax trees and the code, in any language - and especially how it does for how fast you can learn languages.

The demotivation issue though... It's a big one. Banish java, I'm sick of it!
As for C#; I don't like it one bit (and I guess I'd pick Vala over C#, btw) but it does seem to have this one interesting property: it changes significantly and often and it evolves fast.

§ On 5 November 2007, Sunnan wrote: 282
To clarify: I love these "good" languages and I can't see why we have to use the "bad" languages.

§ On 5 November 2007, Sunnan wrote: 283
As for the specific issue; I tried writing an entire program in what I considered "a classic" programming style, similar to my co-workers, less functors, more simple loops like your mutating desc above, and that code turned out to be debugging hell on the algorithm level.

I'm glad you left that delegate-version in, you did the right thing.

§ On 1 January 2008, Gareth wrote: 294
Aren't some of you missing the point.

You are comparing scripting languages with compiled languages - these things /require/ you to program in different ways. If you don't, you aren't really that good a programmer and don't really understand what you are doing!

§ On 1 January 2008, luke wrote: 295
@Gareth: all of the languages I mentioned are compiled:

Haskell is compiled to native code, Python is compiled (to a very simple bytecode), and C# is compiled to bytecode which is then compiled on demand to native code.

You may be thinking about static type checking, but Haskell has far stronger static type checking than C#, so that point would not be valid either.

So, no, the issue is definitely not to do with compiled/scripting languages.

§ On 10 January 2008, Justin L wrote: 297
If your goal is to type less then yes, you don't want C# or Java, and they certainly don't want you. If I shared your goal, I might have rigged up something based on perl, maybe with recursive layers upon layers of hideously opaque perl-based preprocessing. Though, the languages you mention may be even more keystroke-saving-centric than perl, as I almost certainly am out of touch with the "fewer keystrokes means better programming" crowd.

Personally, I absolutely can't stand preprocessing stages, untyped/dynamic languages, and so on, even though they can save keystrokes. I consider them to be a form of unmanaged programming, or in other words, a hack that improves fleshing-out-stage productivity at the cost of reducing the accountability/traceability of your code's behavior.

I mean, in some cases you can accomplish the same task with less typing, and without any disadvantage in terms of readability or traceability. In that case, bravo. However, if you feel it's simply a question of getting the job hacked together with the least keystrokes, having no regard for code quality, then you're missing the big picture.

I'm still kept up at night with nightmares of my unpleasant experiences figuring out where instance.common_member_name was inserted, or why on earth it was a function instead of a number, or where in a project's preprocessing soup a particular statement originated.

Somehow I never look back angrily at the time I could have saved by writing disorganized, unaccountable code, though.

Also, the true character-minimizing language might be base64-encoded binary CISC assembly as a recursive preprocessing layer for itself, coupled with a huge numeric identifier based library. Just a thought for the next time you're "improving" yourself.

§ On 10 January 2008, Justin L wrote: 298
oh and C# now has lambda expressions that might actually make the C# versions of your examples the least keystroke-intensive

§ On 31 January 2008, Jakub wrote: 301
@Justin L
The problem with more code is that it makes things more complicated and creates the effect where one does not see a forrest for the trees.

From experience I know that Python/Java code written by a weak programmer is gonna be bad in both languages.
The difference is when you look at a code written by somebody who knows what they are doing. Python just looks better and it's easier to understand and therefore maintain.

It's not about saving your hands I'm the first one who starts spitting fire if I see an if statement without braces in Java.

On a final note:
I do not think people will ever want to write device drivers in Haskell, C just makes much more sense - and oh device driver in C will result in less code.

§ On 2 February 2008, luke wrote: 302
@Jakub: Thanks for saying that, saved me doing it :-)

On the issue of device drivers, I think an exception might be if you have an operating system written in Haskell -- have you come across House? http://programatica.cs.pdx.edu/House/

Haskell can actually be pretty good at this kind of stuff, using lots of high performance features, such as unboxed structs etc. This is not 'nice' Haskell, but in a Haskell environment, and with experienced programmers, I imagine it could beat C, both in terms of ease of programming and even performance.

§ On 10 February 2008, Mike wrote: 304
I expected to read this article as just another interlanguage flame, but it was well-articulated and thought-out. Thanks for writing it!

§ On 27 February 2008, roger wrote: 305
Haskell is obviously a very good language that's used far too little because managers don't know about thus don't trust it. Then why not not interpersonal skills? One basic rule is that before you
introduce somebody to something potentially threatening, like suggesting a language that's better than the one the manager chose, you have to treat this person really well. Show him that you really appreciate him as a boss as well as personally. Then slowly, slowly discuss the idea of introducing Haskell while at the same you make sure that the boss' decision not to use it was very wise, because it was taken at an earlier moment when it still was not wise to use Haskell. Clearly explain the benefits of using Haskell and discreetly hint that your boss can take all the credit for eventual benefits of it later. Take care of your boss' ego but try to put a rein on your own.

§ On 24 March 2008, Klvson wrote: 307
In the next time, try to make a compare different languages of the same paradigm. Because different programs are best view in different languages. For example, the Quick Sort it's so easy to understand in Haskell, because its own paradigm is recursive, in other hand, it's most difficult in languages like C#.

Different paradigms have different applications.

§ On 14 April 2008, Paul wrote: 317
// Now, in C#:

        class Foo { public String Description { get; set; } }

        static void Main(string[] args)
        {
            var foos = new [] { "meanwhile", "", "", "the", "", "sky", "revolved", "" }.Select(x => new Foo { Description = x });

            Console.WriteLine(
                foos.Select(x => x.Description).Where(desc => desc.Length > 0).Aggregate((x,y) => x + "\n" + y)
            );
        }

Perhaps all those years of FP in Python and Haskell will now pay off!

§ On 6 August 2008, UncleZeiv wrote: 346
Eh eh, this post is actually quite funny... I totally agree especially on the first point.

§ On 6 September 2008, David wrote: 354
A nicer Haskell implementation:

unlines . filter (not . null) . map description

§ On 20 September 2008, chris. harding wrote: 356
Here is a very simple problem. Can some one please tell me how/where to get a module to aviod round off errors to say 1 million decimal places.
Thank you
Chris.

 

§ On 30 September 2008, Luke Palmer wrote: 359
I like Rene de Visser's advice (a very early comment) quite a lot. I have not done programming in any language but Haskell for quite a while, but I have applied that technique even to Haskell. I model my concepts in Coq (a proof system with a very rich dependent type system) first and then take those ideas and "port" them to Haskell. Doing things this way (I have not been doing it long) has given me many insights into how to write cleaner, more meaningful code.

§ On 8 October 2008, Anonymous Coward wrote: 362
Curious if there's possibility to move to F# for you now...

§ On 2 December 2008, Adway wrote: 383
Hi! I have similler tests - Python & GOFER - a variation on Haskell. I have started realizing the beauty of the functional style & hate writing huge number of lines of codes. I also understand the pitfalls in traditional imperative languages.
So, some time back, I plotted with one of my coulligue, to make people in my company aware of functional programming & basically designing through it. You should've seen the response we got. Nobody cared enough for FP (or design for that sake as well). It was a pathetic experience & I learnt that, you can't change the environment.

§ On 3 December 2008, What? wrote: 384
You're comparing C# to Python and Haskell?

I tried making an apple pie with oranges, but it didn't taste anything like apple pie. Oranges make you worse at cooking.

§ On 25 December 2008, JohnMc wrote: 389
Hmmm. Do drive a car with an automatic transmission? Better sell it quick! It makes you a worse driver.

I understand your point. But aren't you complaining about idioms when its the data structure & algorithm that is the critical piece?

§ On 29 December 2008, Anonymous Coward wrote: 390
I only have two things to say:
1) being demotivated over programming languages' features don't make you a good software developer
2) if the environment won't change, you should..

btw, nice piece. makes me wanna try out c# lol

§ On 29 December 2008, david nicol wrote: 391
I am fond of saying:

When I write in Perl, I comment in English; when I write in C, I comment in Perl.

§ On 8 February 2009, Tom P wrote: 403
Similar to Neil (the first responder) I recommend slowly introducing Haskell/Python on non-critical applications.

I had to program in C++ for my main work but whenever someone asked me for a program to help them out (sometimes I even trolled for them :-) ) I wrote it in Smalltalk (this was a few years ago). The result was it began to become accepted (not for my main work though), and I got a good reputation for being helpful and writing quick, reliable code *and* I had a great time learning / using Smalltalk.

§ On 26 February 2009, paniq wrote: 408
heh. searching for "haskell" "python" you are on top of the list, and your post is spot on.

i code python for some time now, and just started getting into haskell to see if i can reduce lines of code and execution time even further.

some light for you: you are allowed to use whatever you want in your free time. make good use of it. you can add these to your vita and switch your job when the time is right.

i was kind of frustrated when i saw gtk2hs. it kind of rapes haskell with its clumsy flat OOP style, and reintroduces everything i was trying to escape from.

i'm dreaming of a graphical functional programming system, but so far i have not seen a single good one.


Closed for comments.