Object-Oriented Lisp and OCaml

Posted by Daniel Lyons Fri, 07 Sep 2007 19:12:00 GMT

I have a theory about the respective OO capabilities of Lisp and OCaml, but I’m not quite sure who to ask.

In Lisp, when you make some class and some methods, those methods look like regular functions. In fact, in a sense, they are regular functions which happen to have more than one definition depending on the types of their parameters. So functional-style programming isn’t hampered.

I’m wondering to what extent functional and OO programming styles intermingle in Lisp and OCaml. My suspicion is that OCaml suffers from a lower degree of functional/OO integration because it provides object#method syntax instead of method object syntax which would be analogous to its function call syntax and closer to Lisp’s (method object) syntax.

Tags , , , ,  | 1 comment

It's Official: Everything is OO

Posted by Daniel Lyons Thu, 09 Aug 2007 05:59:00 GMT

My wonderful arch nemesis Kirit Sælensminde is up to his dastardly old tricks again. Erlang must be officially in the cool now, or else no one would be trying to demonstrate that their language of choice (or invention, to Kirit’s credit) maps perfectly onto it, or vice-versa.

Let’s talk about the semantic differences:

  1. Erlang messages are one-way. All OO languages have call-return semantics.
  2. Erlang’s functions and message passing systems are fully orthogonal.

Erlang is much, much weirder than your run-of-the-mill OO language. But of course we can dig out examples that are different from your run-of-the-mill language—my favorite example is Io. In Io, you can prefix your message with @ to get a transparent future, or @@ to send an asynchronous message altogether. (Of course, let’s forget for a second that Io is implemented with user threads, so it doesn’t scale anything remotely like what Erlang does on huge quantities of processors.) But in Erlang, if you want to return something, you have to send a new message back to the caller. Or two messages. Or none, or whatever.

While we’re thinking of languages with interesting semantics, find me one in which the methods work in a completely different way from the functions. In a decent OO language, you can’t even make a function that isn’t hooked up to a class or an instance.

Also, there are liberties you get with Erlang that you would never get with OO; because the state is just whatever you happen to pass through the listening function. You can call completely different functions when you’re done handling this request, transforming or dropping your state on the floor altogether. This is how you get live code replacement—because there is a boundary between your “behavior” and your “state,” unlike OO where the whole point is to mingle the two ideas.

Then of course we also have implementation differences:

  1. Starting an Erlang process is cheaper than whatever you’re doing (threads, fork/exec, whatever).
  2. Sending an Erlang message is cheaper than executing a method.

I think I’m really getting at two ideas simultaneously and I fear I may be muddying the water. The first is that there’s nothing surprising about computational equivalences between Erlang and OO language X. After all, in C++ all those fancy method invocations wind up being function calls inside the compiler, which in turn wind up being jumps or whatever in the binary. What is surprising and obnoxious is the thought that this computational equivalence implies that language X ought to be as great as Erlang (or whatever other language we’re talking about). We’re not ever comparing the totality of language X and Y, just whatever subsets of each that happen to make the discovery of this equivalence easy.

If there’s nothing new about Erlang’s message passing system, then why doesn’t every OO language have the parallelism benefits Erlang has? Joe asserts that the reason is because Erlang is a functional programming language free of destructive assignment, and, by extension, most of what you think of as being state in an imperative language. Isn’t the whole point of OO that your objects have state and behavior and can be carried around as a unit? If Erlang is OO, it somehow wound up there starting from completely different pieces.

Supposing that Erlang is OO but it got there a completely different way, what makes you think Erlang has any ramifications for language X? It seems possible (putting it mildly) that there is more to a programming language than simply what can be proven about it mathematically. That there are aesthetic concerns and pragmatic concerns well outside what can be proven with math. While we were talking about Erlang from an OO perspective, did we mention the utility of its bit syntax? The closest comparison I’ve seen to it is Haskell’s BitSyntax library and even that’s terrible in comparison. And don’t get me started about aesthetics. An anonymous object with a method on it might be “equivalent” to a lambda abstraction, but look at these two things and tell me with a straight face you wouldn’t prefer the OCaml version to the Java version:

// Java
addWindowListener( 
     new WindowAdapter() {
         public void windowClosing( WindowEvent e ) {
             System.exit(0); 
         } 
     });

(* OCaml *)
addWindowListener (fun e -> System.exit 0)

Erlang is here, now, alive and kicking, gaining in mindshare and popularity every day. It beats the crap out of basically everything else when it comes to concurrency. It has a reasonably large built-in library, it’s been field-tested and really delivered. So what’s with the rush to talk about taking its features to other languages? This is really puzzling to me because Erlang is among my top six languages for implementing damn near anything. I’d vastly prefer it to, say, JavaScript, which is the foundation for Mahlee. JavaScript is a potentially fine language but, as usual from the curly brace contingency, it eschews expressiveness for something like backwards compatibility with menial programmers. Of course semantically I love it, but I love Io so much more I can hardly think about JavaScript. I see it as a web development necessity made tolerable by Prototype, which really is just Ruby for JavaScript when you get down to it.

The rush to pirate the #1 interesting feature from Erlang into various other languages is indicative to me of two things:

  1. Everyone wants easy concurrency right now, and
  2. People do not fully appreciate either the mathematical, pragmatic or the artistic value of a programming language.

If people really were interested in a language as a mathematical principle, then they would only program in languages that map directly onto mathematical formalisms, and they’d chafe at the places where the mapping isn’t perfect. Instead, we rely on math when it’s convenient for us, and discard it the rest of the time.

If people really were interested in a language pragmatically, they would see the value of the language as being a holistic experience. I think there are some truly pragmatic programmers in this world using C, C#, C++, Python and Ruby simply because the combination of the language and the library is best for them. It’s extremely contrary to pragmatism, however, to look at other languages solely in terms of collections of ideas which can be stolen. Languages that are assembled this way are rarely beautiful and never mathematical. In general they come out looking like C++.

If people had a taste for languages as an art form, they would certainly find Erlang to be too beautiful in its own right to want to rush out and copy it. And even if they did, for some reason, desire to do that (perhaps because of some great idea which is impossible in Erlang or merits its own language) they would at least have the artistry to not make it another hard to read, hard to parse nightmare like a curly-brace language. I would, in all seriousness, expect it to look more like Haskell. I’d even take a Ruby/Python hybrid, personally, having the keywords and flexibility of Ruby combined with syntactically meaningful indentation/whitespace.

To return to the topic, it’s very easy to look at Erlang’s message passing and attribute the performance and reliability of Erlang to it. This is an error. Erlang’s performance is not a pure math result, but rather a combination of having a very strong theory supported by a very strong implementation and an environment that encourages coding to a certain aesthetic standard that maximizes the utility of the implementation and theory. Threading can be done correctly, beautifully, and so forth but nothing about threading itself or its implementation in threaded languages in any way encourages this—and threading today is considered expert knowledge, practiced very conservatively by most developers if at all, with the vast majority preferring to write unthreaded code or for systems such as web servers backed by relational databases which mitigate the complexity. Ruby, like Io, uses green threads internally yet by the grace of web servers and databases is used to serve millions of concurrently-generated pages daily by everyone using Rails. (And it’s worth pointing out that its user threading is much poorer than Io’s, which is actually quite good for what it is).

Erlang does everything in its power to help you and encourage you to write concurrent programs the right way. Some of this is syntactic—your messages can be of arbitrary complexity and pattern matching makes it quite simple to decide what to do with a given message. Some of this is semantic—you cannot assign to a variable that’s already bound. Some of it is in the standard library, like OTP, which makes it easy to write servers and monitor them. The whole infrastructure is conspiring with the programmer to the same end. It would be a lie to tell someone, “well, you’ve used OO, that’s message passing, that’s basically the same” because they haven’t experienced it in truth. From this perspective saying “Erlang is OO” is completely meaningless because it’s so much less and so much more than OO is. And simultaneously, to say “If you have asynchronous messages, then you have Erlang” would also be a lie, because it’s like pointing to the engine of a car and saying it’s all there is to it.

A language is so much more.

Tags , , , , ,  | 2 comments

Why Misunderstanding Concurrency-Oriented Programming Sucks

Posted by Daniel Lyons Tue, 10 Apr 2007 07:23:00 GMT

This is a response to Why Misunderstanding OO Sucks.

As systems get larger and more complex then the reductionist view becomes less and less relevant. It continues to have useful inputs into the design, but the development process itself must become more holistic in outlook or it will fail to produce a harmonious whole.

This is an appealing view. It’s of course amusing to throw this at Joe Armstrong, who not only pretty much implemented Erlang but has had his hand in a number of largish systems. If Joe’s perspective were merely reductionist, I’d find it hard to believe that his creation is running the majority of telecom systems in the world. That can’t be a trifling matter.

I think it’s insane to call OO a process and emphasize its effect on software design. If that were the case, how did we have the OO revolution in the 80’s, and not have agile development until the late 90’s? No, if OO had anything to do with process, it had to do with waterfall-model spec, design, then implement thinking. And yet the strongest OO systems today, Smalltalk, Ruby, Python and Io, have nothing to say about the development model, because it had nothing to do with their development or use. If anything, Ruby has a model in agile, thanks to the agile people being overly fond of it.

As for everything being an object, this is only partly true. To make this statement true we have to group together two varieties of object—those with identity and those which are values. Many object oriented languages do in fact conflate these two types of data structure, but of course many do not.

The only OO languages that are a joy to use are those which “conflate” these two things. In Ruby, for example, I can define whatever method I like on integers and call it on a literal, such as the built-in 1.upto(10) { |x| puts x }. Ruby would blow without this feature. In fact, even Python has slowly started to adopt this as a feature. It’s Java and C++, which stupidly maintain a separation between objects and types, that receive the ire of programmers who wish to treat things uniformly.

This difference between object and value semantics is as fundemental to understanding object oriented design and programming as that of function composition is to functional programming. It is unfortunate that it is generally rather badly taught.

I would like to believe that, having been an OO programmer for five years, that statement would have meaning to me, but it doesn’t, for the reasons mentioned above.

If we could build systems that didn’t need to bother with state our jobs would be much easier, but the resulting software would be much less useful and interesting.

That’s interesting, because as mentioned above, Joe Armstrong’s Erlang is now the backbone of the telecom industry, and it doesn’t support modifying your variables. Now, it certainly has state, just like Haskell has state—implicit state, or state managed through a mechanism so alien that OOP isn’t even a concept that can be applied to it.

This shocked me when I started learning functional programming about a year ago. I looked at ML and I snorted. How can this possibly be usable without being able to factor my code into classes? What am I going to do when the client calls me up and I need to have the program do something totally different?

Well, it turns out in functional programming, we have a type system that makes some of OOP unnecessary. Firstly, it’s simple to construct types which enumerate all the different ways of carrying around state you would use in an object. Secondly, we have a pattern-matching system which makes it both possible and cheap to write functions that do different things depending on the nature of their input.

The straw man argument in that is: aha! What about when you add a new alternative to your type, then you have to go through all those functions again and update them! Supposing this is true, consider how hard it is to add a new operation in OO. Say you come up with some new method you need—Aha! You have to go through all those classes and implement that method. And that is the worst case in OO.

OO is, in general, a very good thing when compared to procedural languages. It’s nutty to defend Java and C++ type systems when Ruby and Eiffel exist.

The interesting thing about OO’s lamentable state is quite clear if you look at the history. C++ was made to be as backwards compatible with C as possible. Java was made to be essentially a simplification of C++ with a few improvements. The functional language community wasn’t in a position to have these worries, because these worries come from having a user base, so instead it came up with more and more amazing languages, trying desperately to get people interested.

Actually, this was the second time this had happened. The same thing had basically happened with Lisp in the late 70’s. Everyone was using it and making incompatible variations. Then eventually they decided to have a big standardization process during which the AI winter apparently came and everyone switched to C++. I guess.

What makes the debate bizarre is essentially the Smalltalk factor. While everyone was switching to C++ and lauding the wonder that is OO, how many people were using Smalltalk? It’s not like Smalltalk went away, but it seems to have as many users now as it had after everyone defected for the other. And yet it’s so much more capable and powerful. I find it hard to believe that C bindings could be so difficult or that optimizating compiler technology could be so out of reach when C++ is about the most complex language being used (after FORTRAN or Ada, probably).

In my opinion, I should be spending more of my time worrying about what I’m doing with data rather than worrying about the data itself. OO is definitely interested in helping you worry about the data itself. This is a natural fit for boring business data processing, which is why Java’s being hailed the new COBOL. The crown belongs to the functional languages, but boredom has killed the king.

Tags , ,  | 2 comments