Don’t Believe the Hype

I should begin this with a disclaimer: while I normally try to make these posts well thought-out and to stick to subjects I know a lot about, this time around I’ll be getting a little less neutral and talking a little more about things I have limited experience with. I’m not a functional programming guy, and I’ve never programmed extensively in any sort of functional language. I’ve also never actually tried to write anything serious in Erlang or Haskell or Scala, and the only time I wrote in any kind of Lisp was for one class back in college. I am, in other words, probably not qualified to have the kinds of opinions I have. And of course, as someone pushing a new, as-yet-unreleased language with a more traditional imperative programming model and syntax, my opinions are naturally biased.

But well-founded or not, I do have strong opinions, and the seeming constant parade of blog posts over the last year or two about the rise of functional languages and the coming multi-core apocalypse really kind of annoys me. I think they do a lot more harm than good by focusing too much time and energy on problems that seem “cool” to solve but are largely irrelevant for most developers, and I think they’re generally symptomatic of the fact that a lot of engineers like trying out new toys and enjoy thinking about clever, cool solutions to hypothetical problems sometimes more than they like actually solving real-world ones. To that end, here are the developer hype bubbles I’d most like to see burst.

Multiple Cores And Cloud Computing Will Not Fundamentally Change Programming Languages

This seems to be the primary driver behind a few other misconceptions that I’ll get to next, but the bottom line to me is that programming languages themselves are not going to be heavily affected by the increasing number of desktop cores or the increasing move toward cloud computing. There are several reasons for that. First of all, most web applications already parallelize pretty obviously at the request level. Whatever language you’re writing in, you can spawn a thread or a process per user request (or pool them), and continue on your merry way worrying about threading only when you need to access something like a shared cache. That level of concurrency is already taken for granted by everyone, and generally lets web applications scale up to make use of N processors/cores where N is the number of active users at any one time (ignoring blocking IO and memory constraints, etc.). But after that, it’s generally difficult to parallelize: if your request looks like “add a record to the User table, then read the list of current users and render them to the UI” it’s just not easy to figure out how to parallelize. Could you read data while you’re updating? Maybe, if you have to read some bits of data that you know won’t be updated, or if you can later merge in the results of what you updated. Could you render different parts of the template in parallel? Sure, provided that you knew those parts didn’t interact and had some good way to stitch them back together later, and assuming you wanted to buffer the page in-memory instead of writing straight to the response stream in sequence. At most you could, with a lot of effort, find a way to use an extra core or two here or there. But you’re not suddenly going to make your request->action->response loop use N threads for a single user.

Likewise, desktop applications aren’t going to get all that much more parallel. Game developers already have a tough time using more than a few cores; look at how hard fully utilizing the PS3 is for people. Likewise, iTunes and Windows Media probably aren’t going to start using 16 cores any time soon, and neither is Word or Quicken. Could certain tasks occasionally be split up and parallelized? Sure. But the vast majority of the application code will remain relatively sequential.

In other words, the inability of most programs to take advantage of an arbitrary number of cores is inherent to the problem space, not the result of a lack of proper tools or languages. You could have the best language support for concurrency in the world and it wouldn’t make parallelizing page rendering any easier because you’d still need to do the hard work of figuring out which parts were independent.

The primary ways in which the new multi-core processors will be used will be to 1) offload desktop apps into the cloud, where per-user parallelism is an obvious win by allowing one server to handle work for multiple users, and 2) frameworks that allow for easy parallelism for certain parts of applications, the way web-servers make it easy to parallelize requests per user. But those frameworks really won’t depend too much on underlying language support, at least not to the level that will restrict them only to certain languages (certain languages might do it better, of course, but the bar will really be “good enough” not “optimal”).

There are some problems that lend themselves to parallelism, and those will benefit from more cores and from languages specifically suited to that situation. But for the majority of programmers writing the majority of programs, there’s just not going to be any fundamental shift in how programs are written, regardless of what the hardware guys keep saying. There will be a shift in the frameworks and, more importantly, in where the programs are deployed and run, but not so much in how they’re written.

You’re Not Going To Have To Scale That Much

The Ruby guys have been saying this for a while, every time someone complains that Rails isn’t fast enough: most people just don’t have to scale that much, and those people that do can just add a few more processors or servers. Cloud computing and multi-core processors make that even easier, meaning you have to worry less about some performance issues. Google and Facebook and eBay might have to deal with volumes of data and user requests that make your eyes bug out, but again, they’re an incredibly small subset of the programming population. Scaling to those levels requires some serious black magic and some major architectural changes, but working with those constraints makes everything far more difficult, so you naturally don’t want to impose them on yourself if you don’t have to. Most smaller web-applications can get away with a database server or two and horizontal scaling of servers as they add more users; again, per-use parallelism makes that fairly easy. Scaling at that level still isn’t trivial (you have to load test, know how to performance tune, index properly, optimize queries, and do a ton of caching), but it doesn’t require you to fundamentally build everything with scaling up to 100 million users in mind. Step 1: Build something that works. Step 2: Make it fast enough for your users. Step 3: Worry about scaling to 100 million users when it becomes apparent that you might actually have 100 million users instead of just 100.

Erlang Is Not Going Mainstream

So those two general observations bring me to the point that Erlang isn’t going anywhere. It’s rightly getting attention as a great language to write programs that are massively parallelizable and fault-tolerant (in the sense that individual processes can die and be restarted). But otherwise, the syntax is fairly primitive and restrictive compared to any modern programming language, the tools and libraries are as well, and no one is going to start writing their web application in Erlang instead of using Rails or Django or even ASP.NET, unless they’re doing it just to show off that, “Hey, look, I wrote something in Erlang!” The benefits of the language are negligible for most standard applications. If you need to scale up to 100 million users, would the concurrency advantages potentially outweigh the language disadvantages? Sure. If you’re writing a back-end transaction processing system for a bank, or an instant messaging server that’ll need to handle hundreds of thousands of users, should you consider Erlang? Definitely. Will more than about 1% of software projects benefit from using Erlang? Nope.

Functional Programming Is Not Going Mainstream

Which brings me to a related point, which is that functional programming in general is not going mainstream either. Will languages like Ruby and Python that have some functional ideas in them get more popular? Probably. Will Java potentially add some better functional support? Hopefully. Will “mainstream” developers start writing in Lisp or Haskell or Erlang any other the other functional languages out there? Not a chance. Why not? My theory is that most people just don’t think that way. The real world is imperative and largely sequential; people can really only do one thing at a time, and then do them in order. So if you’re going to make a pb&j sandwich you think in terms of imperative steps: take out ingredients, apply peanut butter to bottom slice, add jelly on top of peanut butter, put on top slice, slice sandwich, eat sandwich. In other words, you’d program it as:

var ingredients = fridge.removeIngredients()
var sandwich = new Sandwich()
applyPeanutButter(sandwich, ingredients)
applyJelly(sandwich, ingredients)
addTopSlice(sandwich, ingredients)
sliceSandwich(sandwich)
eatSandwich(sandwich)

You don’t think of it as:

eatSandwich(sliceSandwich(addTopSlice(applyJelly
                    (applyPeanutButter(removeIngredients)))))

It doesn’t matter whether you think the first version is too verbose, or that side effects are evil, or that the second version parallelizes more easily. People just don’t think that way. They can learn to think that way, sure, but it’s my firm belief that the first version is just how most people’s brains are wired. So people will naturally always be put off by functional programming, regardless of whether or not it’s technically superior. Furthermore, languages like Haskell (and even Scala) have so many complicated concepts baked into the language that most people will just fall back to something easier to use and learn. Sure, monads might be great and powerful and necessary, but anything that takes dozens of wiki pages to explain and multiple tries for most experienced developers is imposing a pretty high barrier to entry. If you’re programming a project just for yourself that you’ll work on for 10 years, and if libraries or platform support weren’t an issue, Lisp (or maybe Haskell) would probably be the right language to write it in. The expressive power and flexibility would let you get more done over time. But if you have to have other people understand your code? Or you need to bring new people onto your team? Wrong answer. The barrier to entry is just too high. It doesn’t matter if something is the best tool if it’s too hard to learn to use, unless you’re the only one that will ever need to use it. And because of that, the libraries and community support just won’t really ever come, which provides a further barrier to entry.

To me, it’s really just a fundamental problem: (most) people naturally think imperatively and will always have an easier time learning imperative languages and reading imperative code, and thus imperative programming is always going to be far and away dominant, regardless of whether or not it’s truly superior in a technical sense.


23 Comments on “Don’t Believe the Hype”

  1. Tony Morris says:

    “I’ve also never actually tried to write anything serious in Erlang or Haskell or Scala, and the only time I wrote in any kind of Lisp was for one class back in college. … my opinions are naturally biased [would you so far as to suggest potentially ill-informed?].”

    A sign of intelligence; I shall continue reading…

    “…you’d still need to do the hard work of figuring out which parts were independent.”

    Were you to understand pure functional programming, you’d know that this hitherto “hard work” is a very central tenet. The others (Erlang and Scala) are just degenerate forms of the solution to this problem.

    I put this rant down to a case of double-think through ignorance. We all do it some time.

    Have a nice day :)

  2. The languages may change significantly, but the way you program will not. The languages that have a low impact will be the ones with the best concurrency support.

    For example, monitors and actors may be considered equivalent at some deep level, but actors use an asynchronous style, while monitors are synchronous. Traditional coding is almost entirely synchronous, so if all other things are equal[1], clearly monitors are the winning approach.

    [1] Of course they’re not equal. Actors can update their code on the fly, while monitors can’t. It’s orthogonal to concurrency though, and not traditionally done, so it’s of low importance. There’s an assortment of similar differences.

  3. Alan Keefer says:

    @Tony – I agree about figuring what’s independent being central to pure functional programming. My point was more that doing that is hard for a large class of problems regardless of the language or tools. Certain languages and programming paradigms naturally make it easier to then exploit that parallelism, and I’d certainly buy the argument that programming in that style trains you to think more in those terms and thus makes it easier over time. But some FP advocates tend to talk about FP as if it’s some kind of concurrency magic bullet, and it’s really not: it’s a good way to exploit independence and parallelism once you’ve found it, but if you can’t find it FP isn’t going to help you.

    @Rhamphornycus – I’d buy that, though my personal opinion is that it’s more likely that transparent concurrency support (where possible) will probably emerge at the level above the language itself in the form of frameworks. Those frameworks will naturally have to be built on a language that has “good enough” concurrency support. I could see a language emerging that helps with that sort of parallelization as well, I just see a framework as more likely.

    To put it another way, I think that it’ll remain the case that most app developers don’t generally have to worry about concurrency all that much, and that a small number of people developing frameworks will have to, but that those people will write in the languages that are easiest for their “clients” to write apps in, not the languages that make it easiest to write high-concurrency frameworks.

  4. I think the underlying frameworks need to be builtin. Monitors need shareability checks, spawning threads need to cancel them if you get an exception, cancelling implies.. cancelability.

    So where does the framework kick in? As a threadpool? That’s just a component. Specialized I/O? We already ruled that out as too much of a style change — traditional blocking I/O is the desired style and the language should make it all cancellable.

  5. Alan Keefer says:

    The vague examples I had in mind might not be very good ones. The first thing that came to mind was the shift to web-applications, where per-user concurrency is both basically free (most of the time) and taken for granted. The second example I was thinking of was something like the Google App Engine, where the language itself doesn’t have to be functional but the framework simply imposes constraints on the language. Another example is something like Hadoop, which is a higher-level framework for doing distributed programming.

    Again, those might not be great examples, but that’s what comes to mind to me: some toolkit that you use where you can write your code, given a set of constraints, in such a way that you generally don’t have to worry about concurrency in the least when you’re writing the core application logic.

    I kind of feel like sometimes we should distinguish between small-scale and large-scale concurrency; when people talk about parallelism are they talking about making something use all 4 cores on a desktop box, or scaling to an arbitrary number of cores somewhere in the cloud? I think there are different solutions to each kind of problem, but that neither of them is going to engender any major shift in language usage.

  6. “you generally don’t have to worry about concurrency in the least when you’re writing the core application logic.”

    I think that’s pretty much the point. Concurrency needs have a *small* impact. Retain normal synchronous coding styles (like you would for a simple single-threaded program). If you ever have to look up a memory model you’ve already failed.

    For small-scale and large-scale I distinguish based on local concurrency and distributed concurrency. Distributed often involves grossly different ways of handling performance (latency), errors (fault-tolerant when a node goes down), and security (untrusted code on remote nodes). That has a strong leaning towards being asynchronous, which is a totally different style, but at the same time you want to keep it to a minimum. Use message passing for certain kinds of communication, but keep as much as you can using a normal style.

    That leads to having builtin concurrency for 90% of uses, but a distributed framework/library for the remaining 10% that are worth the extra efforts.

  7. Carson Gross says:

    Heh. All y’all are too smart for me. Here’s my kind of parallelism:

    Step 1) I realize I need to speed up an operation.

    Step 2) I change

    _myListOfEmployees.sortBy( \ emp -> emp.Salary )

    to

    _myListOfEmployees.parallelSortBy( \ emp -> emp.Salary )

    Step 3) I head off to the pub.

    Long live imperative programming, with closures,
    Carson

  8. Sorry to say Carson, but the first thing that’ll do is slow it down. Single-threaded sorts are highly tuned for what they do. Going parallel adds more overhead, slowing it down.

    In fact, python’s own timsort already has a tendency to be O(n) on many common datasets. Can’t beat that!

    However! Multiple cores is not about changing the big-O. It’s about having a large common factor. By the time we’ve got 64 or 128 cores, that’s a large common factor.

    And when that happens.. the languages will start doing it for you. No need to edit your program, just recompile with the latest compiler.

    Of course that’s about parallelism, not concurrency. Concurrency is what a web server does when it handles more than one request at a time. We need that today, not 15 years from now.

  9. Jason Dusek says:

    Functional programming is more difficult than you let on :)

    However, I think the bit about “But if you have to have other people understand your code? Or you need to bring new people onto your team? Wrong answer.” is no more than FUD. Language heterogeneity is here to stay — folks who write frameworks can expect to support clients who aren’t using the language they’re writing in. This is certainly true of Apache — which is written in a language that relatively few web coders can work with (though they saw it a few times in college). CouchDB is another good example of a framework that is written in a language well suited to its domain and finds use with clients using many different languages.

    To come out swinging against Haskell, List & Erlang, while working on a language with closures and type inference, is more than anything a failure to recognize who you’re real friends are. To suggest we all need to code in a language that everyone is familiar with is both to deny the value of interfaces and to condemn your own language to death.

  10. Jason Dusek says:

    Oh damn, spelling.

  11. I may have been too optimistic. It seems to me that a merge sort’s final merge is O(n), and that can’t be parallelized. It sounds like parallel merge sorts are an academic exercise, not a practical one. If somebody has some better info, I’d like to hear it.

    A more plausible approach is replacing your list with a DBMS’s table, and making sure both your insertion and selects are suitable for scaling up.

    Guess there’s no silver bullet, eh?

  12. Ulf Wiger says:

    In my opinion, multicore already has started to fundamentally change programming in some important commercial niches where concurrency is a natural ingredient. That Erlang applications in these niches get scalability “for free” with multiple cores was neither unexpected nor the main point of using Erlang in the first place. The big win comes from using concurrency-oriented programming as a structuring principle. I’ve found this way of structuring large applications more intuitive than OO.

    Whether or not languages like Haskell and Erlang will become mainstream, I personally don’t care. They are used today for serious commercial development, and programmers who like this style of programming stand an increasingly good chance of finding a place where they can do it for money. Also, These languages influence the mainstream in ways that are quite beneficial.

  13. Carson Gross says:

    Rhamphoryncus,

    Awwwww, c’mon. If my data set is large enough to warrant parallelization, I’ll get a kick out of the parallelized sorting. Of course, if it’s small enough that parallelizing won’t help, well, no other approach is gonna do much for me.

    My point is that, by using closures, we can create data-parallel operations on common data structures that don’t require end-users to know much about parallel computing or concurrency. Smart guys like you can write the implementations and dumb guys like me can use them as needed.

    I agree with your point regarding the database being the right place for this operation though. That’s one reason to admire microsofts LINQ: it makes the highly-parallelizable operations of finding, filtering and sorting data not suck in an OO language. It’s another ingredient in the perfect blend of functional and imperative features necessary for The Perfect Language ™.

    But, yeah, no silver bullet.

    Cheers,
    Carson

  14. My point is that a parallel merge sort is only viable academically. There’s no evidence it’ll be faster than timsort in practice, and there’s good reason to suspect it’ll be much slower.

    In general, automatic parallelization has gotten very little return-on-investment. It has significant overhead and significant complexity, for only modest returns on a very small subset of programs.

    To get better return you need to structure your program with that parallelization in mind, and you might as well use APIs that explicitly allow it to happen. A DBMS is again an example. Another example would be in apache, with a request handlers spread across threads or processes.

  15. Carson Gross says:

    Rhamphoryncus,

    _shrug_

    I think parallelization in general will get us fairly little return on investment at the application level because structuring a program for parallelization ends up meaning creating difficult to debug, non-sequential systems. If I’m given a few easy to use parallelized data-manipulation methods then, in the few cases it helps, I can use them.

    There may be more bang for the buck at deeper points in the application stack (e.g. apache or tomcat) but those sorts of programs have two other things going for them: they are usually very targeted and they are usually written by pretty smart kids who can handle more difficult concurrency problems even with today’s technologies. Us poor grinds who have to write very wide and shallow enterprise apps aren’t in the same position.

    I’ll grant you that the DBMS is a layer that does a great job exploiting parallelism (as well as providing caching and all the rest.) That’s why I’m such a huge fan of LINQ: it makes the declarative nature of SQL look at home in an otherwise imperative language. And, if I’m honest with myself, I agree that that will be far more beneficial for the average enterprise developer.

    Cheers,
    Carson

  16. Alan Keefer says:

    @Jason

    Yeah, that was perhaps intentionally a bit overstated. My point is merely that network effects and barriers to entry matter are a consideration for most people when choosing a language. Most people just aren’t going to go choose a language that 1) only a very small set of people know and 2) is notoriously difficult to become proficient at. That doesn’t mean they’re not good languages, or that they can’t/shouldn’t/won’t be used for projects, and certainly no one really cares what language their tools are written in so long as they can write in their language of choice.

    Again, my main target wasn’t the languages themselves, it’s the hype around the languages. The breathless “multicore changes everything!” and “run out and learn to program Erlang right now!” sorts of posts are, I think, not all that useful. It’s great to expose people to the full range of tools so they can select what’s useful to them, but I think it’s also important to spend time and effort on improving the tools that the vast majority of programmers will use, and to focus on creating mainstream tools and frameworks rather than just on more esoteric, niche things.

    And yeah, I agree that it’s kind of self-defeating as someone who’s helping design yet another programming language. But I kinda got calls ‘em as I sees ‘em in this case.

  17. Carson Gross says:

    Rhamphoryncus,

    Anders has a great, wide-ranging talk up on programming languages and where he sees things going. If you get to around the 54 minute mark, he talks about data parallelism

    http://jaoo.blip.tv/#1324214

    He makes a great point that I didn’t really do a good job conveying: data parallelism is a very syntactically cheap way to test taking advantage of parallelism. No need to massively rewrite your program or adopt strange architectures from the start. The places where parallelism is really going to help you you can sprinkle some on and, in the places it won’t, you don’t pay any additional cost.

    Cheers,
    Carson

  18. Harry says:

    I tend to agree with your view on FP, esp your great pb&j sandwich example. I think this point should make it to the Wikipedia entries on FP, for it very intuitively tells you why FP can be hard to grok by a lot of programmers out there, many of whom are average and solving practical, real-world problems with lot of time constraints. Thanks for sharing your thoughts! /HS

  19. TRW says:

    “You could have the best language support for concurrency in the world and it wouldn’t make parallelizing page rendering any easier because you’d still need to do the hard work of figuring out which parts were independent.”

    You know nothing about the topic on which you speak. Had you known anything about Haskell, for example, you would understand that pure functional code can be parallelized *automatically*. That’s the point, man.

    Ignorance consistently begets confidence. Your post is confidently ignorant.

  20. Alan Keefer says:

    @TRW

    You’re allowed to make whatever assumptions you like about my language knowledge, but I am indeed quite well aware of the fact that pure functional code can be parallelized “automatically.” How much parallelism can be extracted in such a fashion, though, is going to be based on the higher-level algorithm you choose and the data-dependencies therein. My contention was basically that unless you explicitly try to avoid those dependencies by using higher-level algorithms that avoid them, just writing something in a pure functional language won’t lead to sustained usage of multiple cores because the data dependencies in your code will still cripple it. So even if you’re programming functionally with no side effects, you still have to think about parallelism and plan for it just like you would in an imperative language. I’ve also conceded that thinking functionally might help you to structure things that way, and that’s what I think is the real value there.

    I’m always happy to be proven wrong; if someone is consistently able to take single-threaded imperative programs and translate them into functional programs that scale arbitrarily horizontally (or even to an 8-core desktop) without completely rethinking the overall approach, that would be interesting.

    Plain assertions that I’m an idiot and that I don’t understand things that I’ve explicitly addressed in this post, subsequent posts, and the comments to those posts, however, aren’t particularly convincing.

  21. Average Developer says:

    Kudos for writing about this! I haven’t read what you said yet, but I skimmed through all the topics you put here, and, man, it’s about time someone starts addressing these hypes.

    Well, now I’m gonna go read your (printed) post!

  22. Rashid says:

    I couldn’t agree more. I think FP is a new hype.

    Without diving into the discussion of imperative and Functional Programming (FP), my biggest concern about FP is not that we as a programmer don’t understand what a FP is all about; but how to write reusable and readable code.
    All the experts feeding us the idea how beautiful FP is, never mentioned a single word about code reusability and readability. OO paradigm has been a success not because it was technically superior than Functional paradigm and vice versa, but because you can see the whole software as a blue print just looking at the API, and it is so easy to maintain and read someone else code.
    I don’t claim to be an expert of programming paradigms especially FP, but can say it for surety that no FP expert can convince you that reading and maintaining the FP code is the easiest thing to do.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 38 other followers