5 ms·
This argument is absurd. All functional languages have mutable global variables. Most provide explicit support for mutable values (e.g., Scheme, OCaml), but e
by gecko 17y ago
This argument is absurd.
All functional languages have mutable global variables. Most provide explicit support for mutable values (e.g., Scheme, OCaml), but even in the "pure" ones, there are the secretly global mutable values. Clojure gets them from its STM and from classes in the JVM. Erlang stashes them in ETS, DETS, and Mnesia. Haskell shoves them into the IO and State monads (among others) and hopes you won't notice. In all of these cases, the variable changes may be isolated, threadsafe, or internally consistent, or however you wish to describe it, but if that's not mutable state at a global level, I don't know what on Earth you'd call it. In all cases, this means that a function called twice in a row from the same point in a program may return two different values--and that's exactly what the author is saying is a flaw of imperative languages.
Turning things around, while it's theoretically possible that any given function mutates global state in random ways, no good program is written that way. Instead, the relevant state is passed to a function in the form of a struct or class--exactly what you'd be doing in a functional language, as it happens. The only difference is that the function can, and sometimes does, mutate the structure passed to it, whereas the functional equivalent would likely return a slightly different version of that struct. But, again, a combination of passing things conservatively, naming functions well, and making heavy use of const/final/sealed/what have you to lock things down makes this problem largely absent in practice.
I am not saying that functional programming can't a huge improvement for some things. I am utterly convinced that a multithreaded program should be written in a functional way, if not in a purely functional language. I likewise tremendously favor functional languages for algorithm-heavy applications, where the ease and safety with which I can backtrack and memoize can yield huge productivity gains. But saying that all imperative programs have hundreds of arguments, while functional languages have only those defined? Unless you do no output with the outside world, that claim is simply ludicrous.
- cemerick 17y agoSTM, agents/actors, et al. are not "mutable global variables" -- they are all ways of working with state within the bounds of defined semantics. Huge difference, and largely irrelevant to the current discussion. Who said anything about mutating global state in random ways? All you need is to have some state mutated in some way that you aren't aware of to make life hell in an imperative environment. Considering that that happens all the time, especially given the modern conveniences of large frameworks and libraries... > But, again, a combination of passing things conservatively, > naming functions well, and making heavy use of > const/final/sealed/what have you to lock things down makes > this problem largely absent in practice. This is flatly wrong, and equivalent to saying that you can write concurrent code in an imperative environment without a problem as long as you use locks just right.
- jerf 17y ago"Erlang stashes them in ETS, DETS, and Mnesia. Haskell shoves them into the IO and State monads (among others) and hopes you won't notice." A global variable is a variable that is accessible and modifiable at all times in all parts of the program with no particular access control, since the idea of "access control" wasn't even around at the time. C, Python, and Perl all have global variables. Despite your contention, Erlang and Haskell do not. Mnesia, ETS, and DETS all control access via message passing; it's a common misconception but you never get direct access to an Mnesia table and with ETS I think you get a choice of "direct access in one process only" or "ETS spawns a process to manage the table" (not sure about DETS, but I guarantee it still won't be global). How could you even get direct access to a table that may be on another physical server? Mnesia has transactions for Pete's sake; how much less "no particular access control" can you get?! The closest thing to global variables you can get in Erlang is the process dictionary, which is still process-local. Erlang is probably the hardest language I know to have a true global in, because even if you cheat and have a C extension that has a C global in it, odds are that Erlang will still access it via an Erlang process wrapped around it which still has the effect of de facto locking the value into atomic reads and writes. Haskell's State monad does not have anything remotely resembling a "global" value; it is explicitly scoped, labelled by the type system so that you can't cheat your way into it, and it literally desugars into threading functional values through a series of function calls. If that's a global variable, then you've devalued the term "global variable" to the point where every parameter of every function call is a global variable. The IO monad can contain a global value by the definition I gave above, if and only if you use "unsafePerformIO", which is an escape hatch that loudly proclaims "I AM LEAVING PURE FUNCTIONAL BEHIND AND I AM ASKING FOR THE RESULTING PAIN", and, indeed, leaves pure functional behind and asks for the resulting pain. So while that does allow you a global variable, if you really push it, it will actually end up very hard to use due to the difficult-to-predict order of evaluation and isn't a useful thing to do with unsafePerformIO. Otherwise, you only get access to the variable in IO-labeled functions, which except in pathological programs won't be anything like "all functions" and is certainly not globally available to everything. And you'll still need to do some major-league cheating to get access to even the "global" variables I mention here without passing explicit references to them all around; I'm still not sure that's possible without a C extension though I don't know enough to rule it out completely. I can't argue for the other languages you mention since I don't know them. Your argument is flawed, since you have some sort of weirdly potent definition of "global variable" that results in numerous things that aren't "global" getting called "global".
- doty 17y agoIn all cases, this means that a function called twice in a row from the same point in a program may return two different values--and that's exactly what the author is saying is a flaw of imperative languages. For Haskell, this is false. In order to get two different results from the invocation of the same function you must pass in two different arguments. The monadic functions work by yielding a new version of the world, as it were. Here's a nice explanation of Haskell IO that makes sense to me: http://www.haskell.org/haskellwiki/IO_inside http://www.haskell.org/haskellwiki/IO_inside
- Xichekolas 17y agoJust to chip in a link, this explanation was the one that made Monads click for me: http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html http://blog.sigfpe.com/2006/08/you-could-have-invented-monad...
- jrockway 17y agoNot if you use IORefs, foreign calls, unsafePerformIO, MVars, TVars, etc. In all cases except unsafePerformIO, though, the type system ensures that you are prepared to handle this unusual behavior. That's the primary difference between Haskell and the imperative languages. (In Haskell, it's easy to not accidentally use effectful code. In most imperative languages I've used, it is impossible to control your use of side effects.)
- derefr 17y agoWhen people say "Haskell is a functional language," I believe they actually mean "the subset of Haskell that doesn't include unsafePerformIO et all is a functional language." (The fact that standard library functions call those functions is an implementation detail.)
- jrockway 17y agoHaskell shoves them into the IO and State monads (among others) and hopes you won't notice. In both of these cases, if you don't notice, your program won't compile anymore. So really, your statement is the opposite of the truth. Haskell hopes you do notice.
- badoumba 17y agoagree