Blocks != Functional Programming

January 2, 2007 at 6:27 pm 10 comments

Joel Spolsky is one of my heroes. He has a vast amount of insightful articles that rank among the clearest and most relevant software writing today, and his blog gets more hits in a day than mine ever will. (Speaking of which, I hit 2000 visitors yesterday – around 10x more than I ever thought I’d get.) He’s a very smart cookie, and when he speaks, people listen. But last week, while browsing the top Reddit articles of all time, I was surprised to see his article Can Your Programming Language Do This? at #4. While it’s a good primer on Javascript abstraction, I don’t think it deserves as many points as it recieved. I spent the next few days thinking about why this article bothered me so much – Joel certainly didn’t say anything untrue, attack any favorite language of mine, or make some outlandish claim. But then I realized that Joel’s article fit together in a pattern of recent articles, all of which bothered me slightly.

Here’s what I realized: it seems that every language under the sun is being evangelized as an excellent functional programming language simply because it supports a few paradigms from FP.

Or, restated: Anonymous functions do not a functional language make.

The most egregious example of a pundit claiming a language is functional when it’s clearly not is Eric Kidd’s well-known Why Ruby is an acceptable Lisp. Kidd tells us explicitly that Ruby is a denser functional language than Lisp – and I’ll be the first one to admit that if I were to debate the “denser” part of that sentence, I wouldn’t know what I was talking about.

But Ruby is not functional – Wikipedia calls it a reflective, object-oriented programming language, and I agree with them. Yes, you can have block arguments to methods, continuations, generators, reflection, and metaprogramming – but it isn’t functional, for two reasons.

1. It’s hard to carry around functions as objects.

I really don’t know why Ruby hates parentheses so much – it’s probably part of its Perl heritage. In Ruby, you can call methods without sticking superfluous parentheses in there – take a look at this Python code:

" I'll write about Cocoa soon; disaster struck the app I was writing ".strip().lower().split()

Now take a look at the equivalent Ruby code:

" Apple's releasing a tool
with XCode 3 which completely supersedes my Cocoa app - so I'm very depressed right now ".strip.downcase.split

Though you could put parentheses in front of strip, downcase, and split, Ruby will work just fine without them. Now, this feature makes for far fewer parentheses, thereby making code significantly more readable. But what if I want a previously-declared function as an argument? If I type in the name, Ruby will just evaluate the function. Sure, I could use the kludge that is Symbol.to_proc, but that’s ugly – and it wraps the function inside a Proc object, which has to be called with the call(*args) method. And that’s just ugly. In Python, all you need to do is type the function’s name to use it as an object, and append a pair of parentheses if you need to call it.

2. Variables are.

A purely functional language only has immutable variables. Ruby doesn’t. (Yes, I know LISP isn’t purely functional. But it adheres to so many other FP paradigms that we can overlook that.)

But I’m getting distracted, so I’ll cut the above point short.

Anyway, what I wanted to say was this – just because your pet language has support for anonymous functions/closures doesn’t make it a functional language. Sure, Python has lambda and list comprehensions (which are taken from Haskell, a purely functional language) – but it’s not functional, it’s object-oriented. Yes, Ruby has blocks (even if you do have to wrap them in Procs), but it’s not functional. Javascript may have support for anonymous functions, but its syntax can be traced back to Algol and the birth of imperative programming language. Hell, even Objective-C has blocks if you include the F-Script framework, and it’s the farthest thing from functional there is.

In conclusion, don’t say your language is a functional one just because you borrowed a few ideas from Lisp. If you want a real functional language, try OCaml, Haskell, ML, or Scheme. Calling imperative/OOP languages functional just makes the term meaningless.

Entry filed under: code, fp, oop, python, rant, ruby. Tags: .

How to Beat Rails Right Tool, Right Job (?)

10 Comments

  • 1. Scott Stevenson  |  January 3, 2007 at 2:15 pm

    Python’s behavior with parenthesis and function pointers makes me think it was modeled more after C/C++ than Ruby was, which I guess makes sense.

    I love the subtext of this post.

  • 2. Rahul  |  February 3, 2007 at 6:13 pm

    I agree with your post, just want to make a couple of clarifications.

    The reason Ruby doesn’t use parentheses is to blur the distinction between instance variables and methods. myObject.foo could be an instance variable, or it could be a method with no arguments that computes the appropriate value. You don’t know, and the idea is that you shouldn’t care.

    In Javascript, it’s really easy to make anonymous functions (“function (x) {if (x <= 0) return 1; else return x*arguments.callee(x-1);}”) and pass them around, which is the preferred way of setting up callbacks. Javascript 1.6 (implemented in Firefox 1.5+, Opera 7+, etc) even has built-in higher-order functions every(), filter(), forEach(), map(), and some(), though of course you can implement them yourself quite easily. I don’t see why its syntax should be an objection against it being at least commendably close to functional.

    Sorry for the double post, WordPress ate up everything after my less-than character! Shouldn’t there be previews on this thing?

  • 4. Stefan Lang  |  February 3, 2007 at 8:29 pm

    Rahul: (regarding Ruby) “myObject.foo could be an instance variable, or it could be a method with no arguments”

    That’s wrong. It’s always “send message foo to myObject”. What myObject does in reaction to this message is entirely up to myObject. Implementation wise this means a call to method “foo” or if there is no such method, a call to method_missing.

  • 5. rick  |  February 4, 2007 at 12:21 am

    You can grab a reference to a method in ruby with the #method method. http://pastie.caboo.se/37747

  • 6. Eric  |  February 4, 2007 at 3:17 am

    I stand by the claim that Ruby is a reasonable–if impure–functional language.

    Should impurity, by itself, be enough to disqualify a language from being called “functional?” If so, then ML, OCaml, Scheme and Lisp aren’t functional. :-/

    Should support for object-oriented programming disqualify a language? Then OCaml and O’Haskell both fail the test.

    I’d argue for a different criterion: Does the language have first-class functions which close over the surrounding lexical scope? If so, you can bootstrap the entire lambda calculus, and program as functionally as you wish. :-)

    In practice, Ruby has both blocks and true first-class functions. Blocks are sort of mutant pseudo-lambdas, but they lend Ruby code a very functional style. For example, I see stuff like the following all the time:

    [1,2,3].map {|n| n*n }.inject(0) {|x,y| x+y }

    That’s just a map and a foldl, which is as functional as you could ask for, and it’s perfectly standard Ruby style.

    Now, blocks are limited in a lot of unpleasant ways. Fortunately, Ruby has real first-class functions as well:

    f = lambda {|n| n*n }
    f.call(2) # -> 4

    Granted, the call syntax is a bit clunky. But it’s no worse than Common Lisp’s funcall.

    Of course, to be fair, I’m happy to grant that Haskell is a much better functional language than Ruby. :-)

    But if you’re looking for the day-to-day meat and potatoes of functional programming–folds, maps, higher-order functions, and so on–you’ll find a surprising amount of it in good Ruby code.

  • 7. mzz  |  February 6, 2007 at 12:52 am

    Ruby lambda object has [] operator as alias to call. So the example becomes:

    f = lambda { |n| n*n }
    f[2] # 4
    sum = lambda { |x,y| x + y }
    sum[3,5] # 8

  • 8. Stephyn  |  July 19, 2007 at 3:11 pm

    Don’t get me wrong, I love Ruby and I think even from an OOP point of view people should be using things like inject and map instead of iterating over the elements of any array.

    However, even with first class functions a first class citizen’s you lose a lot of the flavor of a function programming language without things like currying/partial application.

    irb(main):002:0> sum = lambda { |x,y| x + y }
    => #
    irb(main):003:0> sum[ 2, 3]
    => 5
    irb(main):004:0> sum[ 2]
    ArgumentError: wrong number of arguments (1 for 2)
    from (irb):2
    from (irb):4:in `[]’
    from (irb):4
    from :0
    irb(main):005:0> sum2 = lambda { |y| sum[ 2, y] }
    => #
    irb(main):006:0> sum2[ 3]
    => 5

    it would be nicer if I could something like:

    sum2 = sum[ 2] # partial application

    AFAIK, there isn’t an easier way to do this that what I did above and that’s very cumbersome. This isn’t the case in Ocaml. I don’t know if Python has partial application or not.

    The nice thing about Ruby is that it may be possible to sit down and re-write call on Proc to automagically return a Proc if the number of arguments is fewer than expected.

  • 9. freeyourmind  |  August 14, 2007 at 6:54 pm

    Well that’s easy:

    class Proc
    alias :old_call :call
    def call (*args)
    if args.length >= arity
    old_call(*args)
    else
    s = ”
    (arity-args.length).times {|i| s += “n#{i}, “}
    s[-2..-1] = ” # eliminate last “, ”
    s2 = ”
    args.each_index {|i| s2 += “args[#{i}], “}
    eval “lambda {|#{s}| self.call(#{s2}#{s})}”
    end
    end
    alias :[] :call
    end

  • 10. Prayevakive  |  November 1, 2007 at 8:42 pm

    ONLINE – DRUGSTORE!
    PRICES of ALL MEDICINES!

    FIND THAT NECESSARY…
    VIAGRA, CIALIS, PHENTERMINE, SOMA… and other pills!

    Welcome please: pills-prices.blogspot.com

    NEW INFORMATION ABOUT PAYDAY LOANS!

    Welcome please: payday-d-loans.blogspot.com

    GOOD LUCK!


About Me



I'm Patrick Thomson. This was a blog about computer programming and computer science that I wrote in high school and college. I have since disavowed many of the views expressed on this site, but I'm keeping it around out of fondness.

If you like this, you might want to check out my Twitter or Tumblr, both of which are occasionally about code.

Blog Stats

  • 551,670 hits

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: