Functions as First-Class Objects

A lot of (the better) programming languages have functions as first-class objects. That means you can pass them around as objects, manipulate them, etc. How can we do this in Ruby? The following doesn’t work:


def hello
puts "Hello, world!"
end

x = hello
x # Doesn't work
x.call # x is not a Proc

Ruby has a lot of complicated machinery to help you do this; it has a Proc class, and allows you (via the yield keyword) to pass in arbitrary code blocks to a function.

Which is nice. But difficult to use, especially if you’re new to Rails (and Ruby).

For Launchpad, we wanted to create a plugin API; we want to be able to create “hooks” that are executed at key points in time (like when a comment is just persisted to the database). What we really want is to store an array of functions, and execute those at a certain time.

How can we do this? Callback functions are nice, but you can’t add multiple callbacks; you can overwrite parts of the class, but that only works once (like callbacks).

The answer is surprisingly simple; Ruby has an eval function you can use to execute arbitrary code. You can do this like:


eval "2 + 2" # => 4

Now, before the screaming hordes of people say “eval is evil!,” I would like to say something. Eval is a tool, like any tool in Ruby; it is very, very powerful, and very useful in certain circumstances (like solving our pluggable architecture problem). But it is dangerous, and very abusable, because it allows you to access arbitrary code (like c.drive.format!). So use it, don’t abuse it. (There are things you can do to set access levels for eval, too.)

How does this solve our problem? Remember that we wanted to store an array of functions; instead of doing that, we can just store the function names, and eval them! Yes, you can’t assume anything about parameters, but still, it’s a good first step.

About Ashiq Alibhai

Ashiq Alibhai, PMP, has been a Rails aficionado since 2007, and developed web applications since early 2003, where he learned PHP in one summer. As the driving-force behind RailsRocket and the Launchpad project, he seeks to share the ease of development with Rails far and wide.
This entry was posted in Development and tagged , , . Bookmark the permalink.

4 Responses to Functions as First-Class Objects

  1. Pingback: Recent Faves Tagged With "eval" : MyNetFaves

  2. George says:

    Procs you use them like this

    lambda do
    print “Hello World”
    end

    call them like this

    prock.call()

  3. Johannes says:

    def hello
    puts "Hello, world!"
    end

    # if you assign:

    x = method :hello

    # then you can:

    x.call # Hello, world!

  4. ashes999 says:

    @Johannes I wasn’t aware of the method keyword; where can I look it up? Is it in the Object class?