The next really big thing will be a language that does not mix things up.
I.e. a language that keeps a clean orthogonality between the three dimensions of a program --state, functionality, and event handling-- not favoring one over the others.
The hard part is to make hierarchical modularization mechanisms work simultaneously along all three dimensions.
We need hierarchy to manage complexity. Complex functions must be decomposed into component functions. Complex data structures must be decomposed into component data objects. And event streams must be decomposed into manageable chunks. Recursively to some degree.
Maybe deep nesting is only a problem because your language does not let you nest all three easily.
I use Haskell and C++ primarily. Haskell has local functions, ADTs, hierarchical modules, and good support for streaming and concurrent operations. C++ has (limited) local functions and lambdas, classes, nested namespaces, iterators, and...well, let’s not talk about imperative concurrency.
These are (mostly) good tools, but I still avoid hierarchy more than one level deep—in my experience it just introduces more complexity than it saves.
Actually, I would disagree with you, based on (1) my personal work and (2) discussions with a variety of other people as I thump the "not all programming needs to be imperative languages" drum.
First, working in a single language allows you to accumulate what, for lack of a better word, I call "IP". Components/libraries/frameworks; a body of work. Having a single language gives you the leverage of previously written code solving prior problems in a debugged fashion.
Second, having a single language allows easier social operation; people can review each others work, a common body of knowledge can form around the language under common use which is difficult to maintain for multiple languages simultaneously.
Third, having a language which is a bit of a melting pot allows idioms to be used in which people are comfortable with their specific idiom - OO/FP, etc.
Personally the only point of contention with FP vs OOP is immutability, or more directly managing state. The distinction between 'simulating people behavior' and 'measuring people behavior' is probably intentionally vague to spur the imagination, but it's quite apt.
Many languages implement multiple flexible looping/filtering structures to discourage shoving everything into for/while loops (which are susceptible to confusing and messy continue, break, goto, yield statements strewn about). Furthermore the rationale behind Clojure[1] is stateful objects are a new kind of spaghetti code, and managing state across scopes requires breaking mental boundaries.
I think the larger problem is referential transparency: most OO languages allow two objects that represent the same states to have distinct identities, even if compare-by-value claims they're equal.
Of course, it's not impossible to have referentially transparent objects. I wrote such a language (Reia)
> most OO languages allow two objects that represent the
> same states to have distinct identities, even if
> compare-by-value claims they're equal.
You can do this in languages that offer only compare-by-value by attaching a unique ID to every object. Of course, you may have to write your own equality relation if you want compare-by-value semantics in addition to compare-by-identity semantics.
This kind-of hearkens back to simulation I think. That is, if two objects have the same properties then it might be useful to identify them as distinct things because they are in fact distinct entities. That they happen to have the same properties is a matter of fidelity only.
Or Rust. Or D. Or Ruby. Or C#. Or Dylan. Or Lua. Or OCaml.
Lots of languages have concepts from multiple paradigms. What is the correct mix of concepts is up for debate.
I honestly believe that Rust has the potential to become the perfect mix for me, but OCaml and D are pretty good second places with the benefit of exponentially greater stability/maturity.
Sure, a lot of those languages (Ruby, C#, Lua) borrow some FP ideas, but I think sprinkling in some FP ideas is different from F#, OCaml, and Scala where FP seems to be more "font-and-center".
My litmus test for whether a language really succesfully marries OO and FP is: how well does a language blend pattern matching syntax and inheritance?
OCaml - basically only gives you pattern matching on primitive types. Object types end up having dramatically different code style
Scala - any syntax that deals with types quickly becomes so complicated that you can't explain it to non-experts
I don't know much about F#.
I've heard that Clojure's core.match grants pattern matching over abstract interfaces in a nice style. It's not an official part of the language, yet, though.
What is complex about Scala's pattern matching? x matches the value x, x:A matches instances of A, A(x) matches if A.unapply(x) evaluates to a Some, and _ matches anything. Erasure throws a wrench into it, but otherwise it's pretty straightforward.
I.e. a language that keeps a clean orthogonality between the three dimensions of a program --state, functionality, and event handling-- not favoring one over the others. The hard part is to make hierarchical modularization mechanisms work simultaneously along all three dimensions.