I agree. For some reason the whole OOP thing got really out of hands and has been force fed into a whole generation of programmers. Yet there's no real evidence that OOP is the right way to go. And then there was the whole Java deal where the "everything is an object" mantra was taken so far that it hurts. The result is probably the most expensive mistake in the history of computing with machines.
> UPDATE: I have a feeling that in 25 years we'll be dissing the current fad du jour - functional programming.
In 25 years, we will be laughing at the present for sure. I just disagree on what that fad is (functional programming is hardly popular enough to be called a "fad", but it's been bubbling under for 30+ years). I think it is dynamic programming languages like Ruby and Python, which to some degree are great but fall apart quickly. Another candidate is Node.js -style asynchronous programming, which will be laughed at once a mainstream language ships with a proper async model like the IO manager of Haskell or Erlang.
It got out of hand, but it's still a rather nice paradigm if you're actually simulating a system or designing a GUI. Teaching it as the One True Paradigm is certainly bad, but it certainly has its uses.
Not really. HTML/CSS/JavaScript combination is not really OO, but works really really well.
In general, I think that any "programming language" for GUI is a fail - we need to develop a declarative approach to GUI (like HTML/CSS, but with more features (e.g. effects) and more emphasis on Application Development (e.g. it's still really hard to create a photoshop-like interface in HTML), less on text presentation).
HTML kind of sucks as a GUI though. You have to work really really hard with Javascript to make it work semi-well.
HTML+HTTP works really well as a way to scale up client / server GUI over a high latency / low bandwidth network. That's its strong point; not that it makes for a good UI in terms of human factors.
In my opinion, even the former notion is to a large extent flawed... Sure, there are several classes of different datatypes that really are different (e.g. mathematical objects, such as vectors, matrices, real numbers, ratios, complex numbers, ..., then strings, channels, binary data, time data...), but most data structures used in most programs are simply either sequences, or maps (dictionaries). I prefer Lisp's/Clojure's approach here - have many functions operating on few data types, as opposed to the inverse.
>I prefer Lisp's/Clojure's approach here - have many functions operating on few data types, as opposed to the inverse.
...that doesn't accurately describe a flaw in Go at all, and stems from a common misconception of Go's type system; namely that it is Java's type system, which it is decidedly not. The interfaces make a big difference.
An interface is simply a set of methods. Any object that implements those methods implements that interface. Adhering to an interface is implicit; you never have to say "type Stanley implements the Cat interface". If the Cat interface is just a "Meow" method, and Stanley can "Meow", Stanley is a Cat.
Take, for example, the io.Writer interface. io.Writer is a method set that contains a single method: the write method. This is the definition for io.Writer:
This interface definition says "a Writer is any object that has a Write method. The Write method must accept a slice of bytes as its only argument, and it returns an integer and an error". Any object that implements this method also implements io.Writer. Therefore, any function that accepts an io.Writer may accept any object that defines this method. (when accepting io.Writer, the object's type is io.Writer; the only thing you can do with an io.Writer object inside of a method that accepts an io.Writer parameter is utilize its Write method, since that's the only thing you know it has).
So, for example, in the encoding/json package, there is an Encoder object. The Encoder object has just one method: the Encode method. This is the signature for the Encode method:
func (enc *Encoder) Encode(v interface{}) error
this method definition reads "the function for the * Encoder type called Encode accepts an interface{} v and returns an error". interface{} is the empty interface; all objects implement at least zero methods, so any object can be supplied; it is valid to pass any object into the Encode method. The returned "error" value will let us know if something has gone wrong.
Now then. We know that we're encoding data to the json format, but to where is it being encoded? Where is the output going? The io.Encoder object embeds an io.Writer object; encoded items are written into the writer. That's a big leap. How do we know which io.Writer to write to? We inject the io.Writer when we create the encoder. This is the signature for the function that creates a json encoder:
func NewEncoder(w io.Writer) *Encoder
It has only one argument; io.Writer. io.Writer has only one method; the Write method. That means that for any data target at all, if you define a Write method, you can encode json to it.
So what io.Writers are commonly found? There is an io.Writer for a UDP socket, a TCP socket, a websocket, an http response, a file on disk, a buffer of bytes, etc. The list goes on.
With this one Encode method, and this one Write interface, we are able to Encode json data to arbitrary targets. There's none of that JSONFileWriter, JSONHTTPResponseWriter, JSONUDPSocketStreamer stuff like you would get in other statically typed languages.
In 25 years, the kids will still be trying to decide which approach is black-and-white "correct", while the experienced will still be using a blend of styles depending on the given problem.
Eliminating side effects sounds brilliant until you start interacting with filesystems or networks. What, you can't memoize those ops or split them across a pmap?
Briefly, functional programming is good at one use case (adding new operations over the data type) and weak at one use case (adding new data type variants), while OO is the opposite (adding new data type variants is easy, while adding new operations is not). You have to choose between OO and FP based on which notion of extensibility is more important to you for the problem at hand (unless you use the relatively exotic solutions of multimethods or the generics trick that Wadler originally proposed).
My takeaway is that OO and FP both have their time and place, and the pragmatic programmer will learn when to use one or the other instead of choosing one camp and bashing the other side.
> UPDATE: I have a feeling that in 25 years we'll be dissing the current fad du jour - functional programming.
Only if unwashed masses start doing a half-baked version of FP without really understanding it. This is what happened to OO. It's similar to what happens to musical genres.