- Imperative code is easier to write than functional code. (At least, its easier to find people who can right acceptable imperative code vs. functional code)
- Some things are inherently single threaded (UI* is the best known example).
- There's alot of C#/C/C++ code out there already, and multiple languages in the same project makes management of said project more difficult.
Personally, I think functional languages will become increasingly mainstream (heck F# itself is a testament to that) but probably never gain lingua franca status like C/C++/Java/C#/etc. have or will.
*This is apparently a somewhat contentious view, so I'll expand upon it.
In a multi-threaded UI, each UI event is dispatched asynchronously and on a thread of its own (the actual management of threads is probably more sophisticated than just spinning up a new one, but that's not really germane to the discussion).
Imagine if this were the case, and you're rendering the window.
- The window manager asks you to draw each element (expect a message, or a function invokation for each element).
- Each element reads its state (implicitly reading the application state)
- Each element draws itself.
In step 2, every element MUST lock the application state (or the subset of it that affects display). Otherwise, in the event the application state is updated, the end result of rendering the window could include elements that reflect two different application states.
This is a lock convoy. Each render thread will lock, render, and then release; therefore they'll execute serially.
Now, imagine you're dealing with user input. First, users are pretty slow so the benefits are going to be non-existent unless you're doing considerable work on the (one-of-many) UI thread; so I'm going to assume thats the case.
- The Window Manager informs your application of user input (once again, message, function call, whatever).
- Read what's needed from the application state. (Locks needed here)
- Spend noticable time crunching some numbers.
- Update the application state. (Locks needed here as well)
All you've accomplished is changing from explicitly starting a worker thread, to implicitly doing so; at the cost of potential heisenbugs & deadlocks if you're loose with locking your state.
The fundamental problem with UI api's is that you're dealing with a many-to-one (or one-to-many depending on how you look at it) relationship. Either many windows, many elements, or many "input types" all of which affect a single window/surface. Some sort of synchronization has to happen, and when it does multi-threading doesn't have any benefits anymore just detractions.