Secondly stuff like LINQ was already available in Smalltalk.
So all those map/filter/fold/.... constructs from lambda calculus, which Java now enjoys.
Then if we apply the modern concept of only Haskell is FP, then there are a couple of FP languages that won't meet the classification.
Ah, and Haskell does not require TCO on their language specification, so it isn't an FP language according to your arbitrary definition.
open Printf;;
printf "After all OCaml isn't a FP language\n";
for idx = 1 to 10 do
printf "%d\n" idx
done
Same goes to Common Lisp, F#, Scala, Clojure.Tail recursion of course is great to have, but you can certainly FP without it, even in a language that supports it. I mean, what if you don't put the recursive call in tail position in a function written in a language that supports tail recursion? It would still be FP.
Just create a static class without member fields where the class plays the role of a poor man's ML module, with all static functions only interacting with their parameters.
Then static import it into the client package.
How to do FP in Java is very well explained in the MIT OCW course 6.005 "Elements of Software Construction", 2008 [1], in particular in lectures 10, 11, 13, 14 & 15.
Remember that you can create closures with inner classes.
As for the fact that in Java you could have state inside, say, a Visitor, the program can still be FP, if you know what you are doing. The point is that when doing FP in a language like Java, you are adopting a definitional approach to FP, which is totally legit: any operation is FP if it is deterministic and has no visible side-effects (a corollary is that then it wouldn't have any observable state of its own, it would be reactive). This is sort of a "if it walks like a duck ..." approach to FP.
In fact, this is exactly what is going on when you are doing reactive programming in a non FP language like Javascript, where there are no restrictions to doing destructive assignment anywhere. This doesn't stop you from doing reactive programming, as long as you follow certain guidelines (because the language won't stop you from infringing them and having state).
How is this possible? The reason is that the OO computation model subsumes FP: anything you can express in an FP language, you can express in an OO language, and then some (although not as naturally, there is more plumbing in the way).
The reverse is not true, and this is a good thing, it is exactly what allows FP to have all those desirable properties.
[1] https://ocw.mit.edu/courses/electrical-engineering-and-compu...
Is time and memory usage a side effect btw? :)
“Optimization” makes it sound as if you could turn it off or on for performance reasons. Instead, programs rely on tail call elimination being in place or otherwise they would not work.
TCO isn't about recursion; it applies to any function call in tail position. Some toolchains only manage to avoid over-allocating stack frames for self-recursive tail calls, but that isn't full TCO, and it doesn't help for other interesting case like mutual recursion, state machines, or continuation-passing style. Compilers which compromise on full support for TCO emit programs with built-in memory leaks; they fail to free data which is no longer needed, and thus unnecessarily exhaust their stack allocation.
Programs which use built-in iterative constructs are still recursive; all that "recursion" means is that the control flow folds back on itself. A traditional "while" loop looks like: (1) stop if a condition is false; (2) otherwise do something; (3) do it again. The "it" in (3) is a recursive reference to the loop.
Now, unstructured explicit recursion is barely better than unstructured "goto", so I'm not advocating that everyone start using tail calls in place of loops. However, bare loops are in much the same position with respect to higher-order primitives such as non-strict folds—and those higher-order primitives are much easier to implement in environments which properly support TCO. Languages where TCO is not customary tend to suffer from a proliferation of built-in constructs—iteration, generators, list comprehensions, coroutines, and the like are all implemented as language features requiring custom code generation, where another language where TCO is customary might relegate such primitives to a library.
There are some recursive structures that are just much more natural than their iterative counterparts. Parsing (as lysium suggests in the sibling post), for example.
But also things like graph and tree traversals, and many search algorithms related to those same structures. If you attempt a tree traversal iteratively, you have to maintain the return stack manually, rather than permitting the language to do it for you (assuming a full traversal and not a search, a search could be done iteratively without much trouble).
The "function" in "functional programming" refers to mathematical functions, which are fixed mappings from inputs to results with no side effects. If your "functions" can have side-effects then they're not functions, they're procedures. Programs composed of effectful procedures are imperative, not functional.