I really liked Guy Steele's opening remarks at OOPSLA'92. It's a good reminder why object-oriented programming has gotten and kept so much traction for the last fifteen years. When you read his notes, remember that he is using procedural programming with C as his baseline. When he says object-oriented programming is good, I think he is saying these three things are good.
- Encapsulation and polymorphism. Objects let you encapsulate data. Virtual methods give you polymorphism. Over C, these are huge levers for structuring and reasoning about code.
- A sound type system. Java and C# provide a static type system in addition, but I think the real benefit over C is simply having a type system that doesn't allow illegal casting.
- Garbage collection. It's a lot to ask programmers to heap-allocate objects without providing automatic memory management. The nice side-effect is that all dynamic memory management gets handled by the collector.
Note that by Steele's reckoning, C++ doesn't count as an object-oriented language. C++ is a huge improvement over C, because it provides encapsulation and polymorphism, but it doesn't fix the type system, and there is no garbage collector.
It's worth observing that functional languages have had all three of these features long before Java hit the scene. LISP had closures, a sound type system, and garbage collection. I think it was Scheme that first introduced lexically-scoped closures, a concept eventually picked up in Common LISP and of course used in all other modern functional languages.
The differences between popular object-oriented languages and functional languages are technically small but profoundly affect day-to-day work. Functional languages provide lambda expressions. Lambda is a primitive that in the right hands can be used to mold just about any scoping mechanism you need. Class-based object-oriented languages are more restrictive, but that lack of choice makes it easier for programmers to decide how to structure their code. There are classes. Define them. Move on.
As for type systems, Haskell probably represents the state-of-the-art in type inference and expressive power in typed languages. Unfortunately, the type system is pretty complex, and type errors can be hard to debug. Java's and C#'s type systems are simpler, less expressive, and require a lot more code to be written. In exchange, they are easier for programmers to understand and use. As for dynamically-typed languages like Scheme and Javascript, it allows for more malleable code in exchange for moving type errors to runtime.
The restrictions on scoping feel confining to functional programmers, but the community at large has pretty much spoken: for the average programmer it's worth the tradeoff. I think the conclusion is much less certain for static type systems versus dynamic type systems. A recent Yegge rant is in large part fueled by Java's static type system. In the last couple of years there has been a surge in dynamically-typed languages such as Python, Ruby, and Javascript. I think that surge speaks volumes: sound type systems have proven their worth but static typing on top of that may not have legs.




