I mean, aside from its obligating name (the Standard Template Library)...
C++ initially intended to present OOP concepts into C. That is: you could tell what a specific entity could and couldn't do (regardless of how it does it) based on its class and class hierarchy. Some compositions of abilities are more difficult to describe in this manner due to the problematics of multiple inheritance, and the fact that C++ supports the concept of interfaces in a somewhat clumsy way (compared to java, etc), but it's there (and could be improved).
And then templates came into play, along with the STL. The STL seemed to take the classical OOP concepts and flush them down the drain, using templates instead.
There should be a distinction between cases when templates are used to generalize types where the types themeselves are irrelevant for the operation of the template (containers, for examples). Having a vector<int>
makes perfect sense.
However, in many other cases (iterators and algorithms), templated types are supposed to follow a "concept" (Input Iterator, Forward Iterator, etc...) where the actual details of the concept are defined entirely by the implementation of the template function/class, and not by the class of the type used with the template, which is a somewhat anti-usage of OOP.
For example, you can tell the function:
void MyFunc(ForwardIterator<...> *I);
Update: As it was unclear in the original question, ForwardIterator is ok to be templated itself to allow any ForwardIterator type. The contrary is having ForwardIterator as a concept.
expects a Forward Iterator only by looking at its definition, where you'd need either to look at the implementation or the documentation for:
template <typename Type> void MyFunc(Type *I);
Two claims I can make in favor of using templates: compiled code can be made more efficient, by tailor-compiling the template for each used type, instead of using vtables. And the fact that templates can be used with native types.
However, I am looking for a more profound reason why abandoning classical OOP in favor of templating for the STL? (Assuming you read that far :P)
The most direct answer to what I think you're asking/complaining about is this: The assumption that C++ is an OOP language is a false assumption.
C++ is a multi-paradigm language. It can be programmed using OOP principles, it can be programmed procedurally, it can be programmed generically (templates), and with C++11 (formerly known as C++0x) some things can even be programmed functionally.
The designers of C++ see this as an advantage, so they would argue that constraining C++ to act like a purely OOP language when generic programming solves the problem better and, well, more generically, would be a step backwards.
Why a pure OOP design to a Data Structure & Algorithms Library would be better ?! OOP is not the solution for every thing.
IMHO, STL is the most elegant library I have seen ever :)
for your question,
you don't need runtime polymorphism, it is an advantage for STL actually to implement the Library using static polymorphism, that means efficiency. Try to write a generic Sort or Distance or what ever algorithm that applies to ALL containers! your Sort in Java would call functions that are dynamic through n-levels to be executed!
You need stupid thing like Boxing and Unboxing to hide nasty assumptions of the so called Pure OOP languages.
The only problem I see with STL, and templates in general is the awful error messages. Which will be solved using Concepts in C++0X.
Comparing STL to Collections in Java is Like comparing Taj Mahal to my house :)
For a moment, let's think of the standard library as basically a database of collections and algorithms.
If you've studied the history of databases, you undoubtedly know that back in the beginning, databases were mostly "hierarchical". Hierarchical databases corresponded very closely to classical OOP--specifically, the single-inheritance variety, such as used by Smalltalk.
Over time, it became apparent that hierarchical databases could be used to model almost anything, but in some cases the single-inheritance model was fairly limiting. If you had a wooden door, it was handy to be able to look at it either as a door, or as a piece of some raw material (steel, wood, etc.)
So, they invented network model databases. Network model databases correspond very closely to multiple inheritance. C++ supports multiple inheritance completely, while Java supports a limited form (you can inherit from only one class, but can also implement as many interfaces as you like).
Both hierarchical model and network model databases have mostly faded from general purpose use (though a few remain in fairly specific niches). For most purposes, they've been replaced by relational databases.
Much of the reason relational databases took over was versatility. The relational model is functionally a superset of the network model (which is, in turn, a superset of the hierarchical model).
C++ has largely followed the same path. The correspondence between single inheritance and the hierarchical model and between multiple inheritance and the network model are fairly obvious. The correspondence between C++ templates and the hierarchical model may be less obvious, but it's a pretty close fit anyway.
I haven't seen a formal proof of it, but I believe the capabilities of templates are a superset of those provided by multiple inheritance (which is clearly a superset of single inerhitance). The one tricky part is that templates are mostly statically bound--that is, all the binding happens at compile time, not run time. As such, a formal proof that inheritance provides a superset of the capabilities of inheritance may well be somewhat difficult and complex (or may even be impossible).
In any case, I think that's most of the real reason C++ doesn't use inheritance for its containers--there's no real reason to do so, because inheritance provides only a subset of the capabilities provided by templates. Since templates are basically a necessity in some cases, they might as well be used nearly everywhere.
My understanding is that Stroustrup originally preferred an "OOP-styled" container design, and in fact didn't see any other way to do it. Alexander Stepanov is the one responsible for the STL, and his goals did not include "make it object oriented":
(He does explain why inheritance and virtuals -- a.k.a. object oriented design "was fundamentally flawed and should not be used" in the rest of the interview).
Once Stepanov presented his library to Stroustrup, Stroustrup and others went through herculean efforts to get it into the ISO C++ standard (same interview):
STL started off with the intention of provide a large library covering most commonly used algorithm -- with the target of consitent behavior and performance. Template came as a key factor to make that implementation and target feasible.
Just to provide another reference:
Al Stevens Interviews Alex Stepanov, in March 1995 of DDJ:
Stepanov explained his work experience and choice made towards a large library of algorithm, which eventually evolved into STL.
The short answer is "because C++ has moved on". Yes, back in the late 70's, Stroustrup intended to create an upgraded C with OOP capabilities, but that is a long time ago. By the time the language was standardized in 1998, it was no longer an OOP language. It was a multi-paradigm language. It certainly had some support for OOP code, but it also had a turing-complete template language overlaid, it allowed compile-time metaprogramming, and people had discovered generic programming. Suddenly, OOP just didn't seem all that important. Not when we can write simpler, more concise and more efficient code by using techniques available through templates and generic programming.
OOP is not the holy grail. It's a cute idea, and it was quite an improvement over procedural languages back in the 70's when it was invented. But it's honestly not all it's cracked up to be. In many cases it is clumsy and verbose and it doesn't really promote reusable code or modularity.
That is why the C++ community is today far more interested in generic programming, and why everyone are finally starting to realize that functional programming is quite clever as well. OOP on its own just isn't a pretty sight.
Try drawing a dependency graph of a hypothetical "OOP-ified" STL. How many classes would have to know about each others? There would be a lot of dependencies. Would you be able to include just the
vector
header, without also gettingiterator
or eveniostream
pulled in? The STL makes this easy. A vector knows about the iterator type it defines, and that's all. The STL algorithms know nothing. They don't even need to include an iterator header, even though they all accept iterators as parameters. Which is more modular then?The STL may not follow the rules of OOP as Java defines it, but doesn't it achieve the goals of OOP? Doesn't it achieve reusability, low coupling, modularity and encapsulation?
And doesn't it achieve these goals better than an OOP-ified version would?
As for why the STL was adopted into the language, several things happened that led to the STL.
First, templates were added to C++. They were added for much the same reason that generics were added to .NET. It seemed a good idea to be able to write stuff like "containers of a type T" without throwing away type safety. Of course, the implementation they settled on was quite a lot more complex and powerful.
Then people discovered that the template mechanism they had added was even more powerful than expected. And someone started experimenting with using templates to write a more generic library. One inspired by functional programming, and one which used all the new capabilities of C++.
He presented it to the C++ language committee, who took quite a while to grow used to it because it looked so strange and different, but ultimately realized that it worked better than the traditional OOP equivalents they'd have to include otherwise. So they made a few adjustments to it, and adopted it into the standard library.
It wasn't an ideological choice, it wasn't a political choice of "do we want to be OOP or not", but a very pragmatic one. They evaluated the library, and saw that it worked very well.
In any case, both of the reasons you mention for favoring the STL are absolutely essential.
The C++ standard library has to be efficient. If it is less efficient than, say, the equivalent hand-rolled C code, then people would not use it. That would lower productivity, increase the likelihood of bugs, and overall just be a bad idea.
And the STL has to work with primitive types, because primitive types are all you have in C, and they're a major part of both languages. If the STL did not work with native arrays, it would be useless.
Your question has a strong assumption that OOP is "best". I'm curious to hear why. You ask why they "abandoned classical OOP". I'm wondering why they should have stuck with it. Which advantages would it have had?