The problem was, back in 83 the compiler was the size and complexity of a C++ or java compiler from 1995. Couple that with some horrible implementations and Ada never took off much beyond Avionics/security/life critical applications.
Which is a shame, because comparing ada to C++ or java today and imnsho Ada wins hands down. The compilers are faster, the code very nearly as fast (In Ada you get things like runtime array checking which slows you down). Unfortunately the programming language wars aren't about technical merit (Java would never have been popular otherwise) and more about social popularity contests/network effects.
EDIT: I might add that at this point ada is /far/ simpler than both c++ anda java. Jean Ichbiah thought carefully about what was needed for large, long lived projects (millions of lines, 30+ years life) and it shows. They got pointers right the first time - access types. verifiability - testing your code is all the rage now, 27 years late. etc. Best yet, the ecosystem around the language is mature. That is unlike c++ you don't have a dozen different approaches taken (template hell), and unlike Java you don't have bureaucratic overload.
There is no real argument made one way or another. If we look at the linked article there are real arguments as to why people don't like C++. Templates, multiple inheritance, and a whole other range of stuff. All Linus is yelling is "I hate C++, I hate STL, them Boost guys aren't worth anything" with absolutely no reasoning what so ever.
As a project leader it is okay for him to disagree about using C++ within his source code base, and within context it is a perfectly valid email, but to use as an example as to why C++ is bad, it is a very bad email to quote.
You may not like it, but it is extremely effective, and Linus _is_ herding thousands of developers, he has to be effective.
Why do we excuse bad behavior from people?
Now I agree that for a host of reasons (like taking one's own volition for the country's CEV), dictatorships do not rank high.
I mean, do you remember the C written in the 80s? Often, the only unit of modularity in common use was the translation unit, with static globals used freely, structures with no visibility protection, having their inner guts manipulated by different modules, frequently by manually tweaking the pointers etc.? If you had an API that protected structural guts, you were almost always essentially programming to an object oriented style, only with no help from the language and compiler.
And then, of course, you have mergers and acquisitions leading to code being thrown away or warehoused or merged with other systems, or new management deciding to start from scratch.
Basically, the industry doesn't really have a long enough attention span to really make the most of OO code reuse.
I think the people making this criticism are looking in the wrong place for the reuse, and / or had weird ideas of what could be reused, and how it could be reused, to begin with.
The reuse that OO gives us comes from raising the level of abstraction with which the program is written, in particular because runtime libraries are so much larger ("batteries included", etc.). The hierarchical namespaces and encapsulated structure of modern class libraries reduces their cognitive overhead. For example, in .NET, you can work with WebRequest, TcpClient or Socket, depending on what level of control you need; and the conventions for working with these things are pretty uniform across the board. Larger applications are self-similarly written at a higher level, reusing code within themselves in a framework-like way.
But the people who thought there was going to be some kind of central library of domain-specific classes in your company, that you would reuse in multiple disparate applications, I think that was always fairly naive; reuse implies coupling, and coupling of things that are individually subject to change in ways that affects their users is fraught with problems, and always has been.
The best candidates for reuse aren't usually representations of the domain concepts that are central to a business, because each application in the business will probably be wanting to do something quite unique with those domain classes. Rather, it's concepts that are self-contained, universal, not likely to change much over time nor need different intrinsic behaviour from application to application, which are best suited to reuse.
How much of that is due to OO, though? I reuse masses of code without OO all the time.
Well, perhaps, but I've seen it done successfully in NeXTSTEP/OpenStep shops back in the day, such as an investment bank. Not one big library, but a few frameworks so there's some separation.
The team I was on had our own frameworks, shared among the apps we developed. We also used/built our frameworks on frameworks from the bank's Architecture group, which were also used by other development groups.
One way they justify this is to 'reduce coupling', and so your comment about coupling tripped a red flag for me. Whenever I want to take the piss out of an Architect I just tell them that we should 'add an extra layer of indirection' to the design. 99% of the time they agree without realising that I'm satirising them.
Actually, this could be a good thing, depending on what the goals were. For example, non-member non-friend classes are often more OO than putting everything into the class[1]. Furthermore, if you want to use function overloading for multiple dispatch, the keeping the functions separate from the objects is also useful. If your system is highly concurrent, keeping the code and data separate can be quite helpful. Also keeping data in structure-of-arrays form and using external functions to operate on these arrays can make huge differences in terms of cache usage, potential parallelism and vectorization of instructions.
Coupling might be a reason to do this, but its certainly not the first reason I think of. There are plenty of better reasons (and as always, not all reasons apply to all codebases).
TL;DR: There are lots of reasons why doing this could be a good thing.
(fwiw, I like to do this with my core data structures because I believe code and data should be kept separate (and that data is the more important of the two). I do like to provide normal objects as an API though, because I often feel that its a natural interface, but the internals of my code are rarely very OO in the C++/Java sense).
Having said that, there are some things OO is bad at, eg concurrency.
OO prioritizes encapsulation ahead of immutability as a way of making the problem of a mutable struct tractable. Most OO programs are graphs (picture as a complex web) of mutable objects holding references to one another, synchronously passing control from one object's method to the next (picture as a spider travelling around the web, making modifications). Concurrency means there is more than one logical point of control flowing around the graph, making modifications. To ensure modifications are consistent, one must now fight against the interconnected nature of this graph, and make certain areas mutually exclusive; that means you need to set up gates on all the edges leading into those areas (often called semaphores or mutexes).
But OO gives you precious little help in setting aside these areas, and guaranteeing internal consistency in the face of multiple mutating points of control.
Programs in a functional style are different, with their heavy emphasis on immutability. In this case, the web, as it were, is fixed and cannot be changed; instead, if there is to be a modification, a new copy is created (possibly only of the local area of change, and the unchanged portion included via references). Since there is no way to change data, there can be as many points of control performing operations as desired. (Actually, one of the models of computation used for functional programs is that of graph reduction, which pictures the program as a web of expressions rather than structures; and that big expression is iteratively made smaller by calculating different parts of it. In principle, the more points of control you have doing these calculations, or reductions (in the same way as '1 + 2' can be reduced to '3'), the better.)
Programs written in an agent / actor style are also different. Here, there is no single point of control flowing from one node in the graph (web) to the next; instead, each node has its own little point of control, and it reacts to messages coming in from each edge, and sends out messages along edges in response. This makes the program locally single-threaded, but globally concurrent.
But there are moderating factors. Procedural programs that don't enforce strict modularity conventions tend to be bound in size by their complexity, a complexity that works against the level of understanding necessary to make things both concurrent and correct. Meanwhile, procedural programs that do enforce strict modularity will probably be using conventions that emulate a different paradigm, and will inherit that paradigms' costs and benefits WRT concurrency.
But Java naturally tends towards mutability. And you will have to work harder to make it immutable. Java also does not give you as many tools for this kind of style as functional languages usually give you.
First class functions, a rich type system and a library full of immutable data types come to my mind.
Worse, OOP tends to hide the mutable state away internally in objects (or in objects stored inside objects etc) - OOP's data hiding and abstraction support can go against you here. Sure, good programming practices and discipline (eg, const correctness in C++) helps, but the languages definitely encourage mutable state.
I wonder how using methods-as-messages and turning OOP into a message passing system not dissimilar to the actor model would work in practice (both from a usability/syntax and concurrency view).
Now, do you see a significant additional boost that were provided by the various OO styles out there? More specifically, what significant advantage do classes have over modules?
[1]: http://blog.c3lang.org/aims-and-rules-of-thumb-for-the-desig...
http://yosefk.com/c++fqa/heap.html#fqa-16.26
"C++ does not feel pain. It can't be reasoned with. Starting a fight is a big mistake. If you want to use C++, you must learn to love it the way it is, in particular, manage your memory manually."
1 - Error handling - Go doesn't have any powerful mechanism for error handling. The code I have seen is rather inconsistent and it doesn't solve the main problem from C of forcing people to handle errors.
2 - Polymorphism - They left any kind of generics out. I think this could go a long ways for (1) too, just look at Either or Maybe type in Haskell. Combine this with some pattern matching and you have a really powerful way to enforce error handling and have polymorphic data structures and functions. IMO this is the biggest failing of Go.
I think the failure to provide those two things also makes Go a future mess. Adding them later either breaks a lot of outstanding code or it means you have to versions of Go, the original and new which is a mess.
Actually, the creators of Go are still not afraid of breaking things. For example, recent release (2011-02-01.1¹) changed the syntax of non-blocking channel operations, and it broke code.
[1] https://groups.google.com/d/topic/golang-nuts/uHfjRyO1Q6c/di...
It says something that for the built-in collection types, Slice and Map, they had to hack around their own API and implement this-case-only ad hoc generics. Slice and Map should be fully implementable within the language.
However, the make() functions for slice and map are the only functions in the language that allow you to pass in a type and get that type back as a return function. Why can't users have that functionality? Generics seem to be the easiest way to get it.
myslice := mymake((MyType)(nil), 10).([]MyType)
which is much uglier than the built-in way. However, I'm kinda okay with reflection-laden runtime tomfoolery looking a bit messy, mostly because I rarely use it, and when I do I like it to stand out and be obvious what is going on.
Anyway, it's not like a wannabe OO language would adopt Algebraic Data Types. "Those are for these ivory tower languages that no one use in the real world", one might say.
Qi: http://en.wikipedia.org/wiki/Qi_%28programming_language%29
Why then, you might complain, have we not seen the benefits of OO? Because the majority of programmers (usually by their own admission) suck at design.
For a more current view, see Linus Torvalds' comments [1] [2].
What I would like to see is a language very much like C (being low-level) with a few features built on top. What those features are I guess is the real trick.
One thing I like about C++ is the constructor/destructor mechanism. It's very explicit. The trend now is towards garbage collection (which, admittedly, you can implement in C++). This is a trend I largely agree with. It's quicker and cheaper to write software that way (IMHO). But there is still a place for simper schemes as all GCs I've come across have issues.
One thing I think such a language shouldn't be is object-oriented. To quote Joel Spolsky [3]:
> A lot of us thought in the 1990s that the big battle would be between procedural and object oriented programming, and we thought that object oriented programming would provide a big boost in programmer productivity. I thought that, too. Some people still think that. It turns out we were wrong. Object oriented programming is handy dandy, but it's not really the productivity booster that was promised.
Or at least such objects should be very limited in scope. Linus addresses some of the reasons for this, such as knowing which function is being called by simply looking at a code snippet (typically a patch in his case).
When writing low-level code I certainly do much prefer C over C++. But having the tools to build automatic reference counting into C would be really nice at times.
[1]: http://thread.gmane.org/gmane.comp.version-control.git/57643...
[2]: http://www.realworldtech.com/forums/index.cfm?action=detail&...
[3]: http://www.joelonsoftware.com/articles/APIWar.html