One thing that I'll agree is more "magical" for functional language is the transformation from functional code to efficient machine code. It's not obvious how Haskell can achieve such high performance when it makes almost no concessions to the underlying architecture of the computer. On the other hand, it's usually pretty clear what kind of assembly your C will turn into. This can make performance estimation more difficult.
C(++) has undefined behavior because it's meant to run close to metal, and there's no official standard of CPU design.
If anything, a C compiler could always insert an "if" in a non-standard arch on every signed addition to get it to overflow the "right way".
The thing is that it would ruin performance.
And the proof is that Java, which was quite imperative, doesn't have nearly as much undefined behavior as C.
You're right, but Java is still orders of magnitude less predictable than Haskell. A few good links here.
http://stackoverflow.com/questions/376338/what-are-the-commo...
It essentially boils down to a combination of unsound type systems and underspecified semantics. Java was not created on a sound theoretical basis - it's quite ad-hoc.
In a (strict) functional language, foo(bar) always returns the same way and always has the same affect.
In almost every non-strict language foo(bar) can do anything, and can always be different based off some state not contained in foo or bar, but only the scope of the program.
So while mathematically they may both be equally as predictable at the physical level, given only a function its parameters, a strict functional language is predictable while a 'traditional' language is not
\x y -> g (f x) (f y)
We have no way of knowing what this function will do, because f and g are free variables with respect to the function. But we assume they are constant, so we're happy. And if you zoom out far enough eventually you'll find the binding locations.Instance members and globals are just the imperative version of free variables, and if it weren't for that pesky assignment operator or mutable primitives, they'd be constant and hence completely harmless too.
You could imagine an OO language without assignment or mutable primitives that would have all the advantages of "functional" languages but that would still feel different enough in style that we wouldn't call it one.