Friday, December 4, 2009

Down, Down, Down

So, back to the stacks. This time it's about functions and methods and objects and functions and methods and objects.

So, as I mentioned only briefly, functions are really objects that implement a particular method, namely operator(). This is nice because it means that we can easily define functors and use them in the same way we use "regular" functions and object methods. For instance, the following class wraps an "action" (for those of you not from the C# world, a unary function returning void) and returns an action that keeps track of how many times it has been called:

class CountedAction
{
  private var func;
  private var count = 0;
  
  public operator()(arg)
  {
    this.count++;
    this.func(arg);
  }

  public Count()
  {
    return this.count;
  }
  
  public Reset()
  {
    this.count = 0;
    return;
  }
}

Now, to be fair there are other ways we could swing this sort of thing, but I'm not as concerned with what is possible so much as I am with what is simple or even elegant.

So, what we'd like to say is that, whenever we call an object, we simply look up that object's operator() and call that. Of course, here be our turtles.

Retraction, start over. Let's say first that a callable object is either a "real" function, or it is an object which has a member operator() that is itself callable. Then calling an object consists of either actually calling it (in terms of typechecking, it means creating a new environment with bindings for each function argument and then checking the function's body) if it is a "real" function, or it proceeds by retrieving the object-to-be-called's member operator() and calling that with the given arguments.

That's a bit better, but it means that the programmer has to deal with both objects and these "real" functions, when the whole point of this mess is to treat everything as objects. So it remains for us to hide this additional complexity in the language, so that the programmer can pretend that everything is an object, and that anything implementing operator() can be called.

It's pretty easy to see that any "real" function can be easily treated as an object that has a single member, operator(), whose body is the exact same as the function. So in the end all we have to do is, whenever a "real" function is used in any way other than being called, promote it to an object.

That's great, and thus topples our turtle stack. But what's the end result for me? Well, one nice thing is that now all functions and methods can be treated uniformly. For instance, consider the following class definition:

class Foo
{
  BarMethod(a)
  {
    return a.Bleck();
  }
}
That's equivalent to the following:
class Foo
{
  private var BarMethod;
  new()
  {
    this.BarMethod = function(a){ return a.Bleck(); };
  }
}

All because methods are just functions; see this post for more information on how methods are implemented in this way. And now I'll say goodnight.

No comments:

Post a Comment