Monday, April 23, 2007

Objects, just not Object Oriented

I've been on a real programming language kick for the past year. First, I picked up Prolog again. Then Javascript, then Ruby, then Lua, then Erlang. This is in addition to lots of programming in C#, some in Java, and a little C++ on the side. I'm starting to notice lots of similarities between languages. I don't mean superficial similarities (Java has classes. Whoa, so does C#. Dude...). I mean deeper, conceptual similarities.

As an example, take objects. C++ has objects. Smalltalk does too. Also Java and C# and a whole lot of other languages. However, all of the objects in those languages are bound together by sharing a single class.

Javascript and Lua don't share that requirement. They're still object-based (you have entities which hide implementation and expose functionality), but object's don't necessarily share a common class. In fact, an object in these languages can (and often does) have no class at all.

Further still, some languages have object-like things. Erlang, for example, allows you to create processes. Processes can send messages to each other. Processes can even have private data (since a process is just a function, and functions can always have local variables, processes can have private data). Is this an object? I think so!

Some languages even give you object-like functionality in even stranger ways. Take purely functional languages like Lisp (or Scheme) or ML. These languages let you create "closures". A closure is a function that exists within (is closed to) an environment. In Javascript (not a functional language, but one which supports closures):

function make_add(left_addend) {
var f = function(right_addend) {
return left_addend + right_addend;
}

//At this point, f is bound to left_addend. Whatever
//we passed in as left_addend is now known by f.
//We can return f, and it will correctly remember
//the value of left_addend.

return f;
}

var add10 = make_add(10);
var add1000 = make_add(1000);

print_to_console(add10(5));
print_to_console(add10(50));

print_to_console(add1000(5));
print_to_console(add1000(50));




15
60
1005
1050


Why is this cool? Well, we have effectively created an entity which has private data. We could go a step further and make 'f' into some sort of dispatch method. It could take, as its first parameter, an operation. So, perhaps we could have this:

function make_number(value) {
var f = function(operation) {
if (operation == "add") {
return make_number(value + arguments[1]);
} else if (operation == "sub") {
return make_number(value - arguments[1]);
} else if (operation == "toString") {
return value;
} else {
return null;
}
}

var number10 = make_number(10);
var number1000 = make_number(1000);

print_to_console(number10("add", 5)("toString"));
print_to_console(number10("sub", 50)("toString"));

print_to_console(number1000("sub", 5)("toString"));
print_to_console(number1000("add", 50)("toString"));




15
-40
995
1050


Not too pretty, but it should work. Object-oriented programming in functional languages. Who knew?

No comments: