7 ms·
Why care about functional programming? Part 1: Immutability
- deepsun 12y agoNo one prevents you to use immutable structures in OOP. Getting some help from language is nice, but after 10+ years of programming all those patterns (e.g. immutable) become so natural, that you don't really think much about them. Because you know what data structure you want, and see what language offers you. So the whole "which language" deal doesn't make so much difference (although it's easier/harder in some languages). Tooling/libs and community matters way more.
- the_af 12y ago> No one prevents you to use immutable structures in OOP. No one prevents you, but what about the code other people write?
- deepsun 12y agoGood point. Fortunately, I had pretty good engineers in my recent teams, but, remembering my older projects, I totally agree with you that it's good when language makes it hard to write bad code for less competent engineers.
- fallat 12y agoYou've hit the nail right on the head. People praising FP don't realize (but start to after awhile) that you should combine the FP paradigm with /OTHER/ paradigms as well. Your arsenal of patterns will help you write code. Don't limit yourself to one.
- sklogic 12y agoAs long as there is no decent pattern matching in most of the OO languages, they're pretty useless. No matter how big is community and how hip is tooling.
- phkahler 12y agoThat's an awful lot of text to advocate for immutable data to prevent shooting yourself in the foot when things go concurrent. I've got this renderer that takes a huge data structure and uses simple OpenMP constructs to draw images. There is an assumption that the underlying data will not change during a render. Do I need a functional language to enforce this? No. Would it be nice if C++ had a feature to enforce it? Yes. Will I eventually want to make something that can carefully modify the data while rendering? Maybe, but I'm not sure that even makes sense. I think a bigger threat is event driven code which IMHO is notorious for making things happen in unexpected order.
- sirseal 12y agoI'm not that great at C++, but can't you use the const keyword to declare that something's value isn't changing?
- tjradcliffe 12y agoYou can. If you want to write immutable C++ simply declare every single variable const. Done. The only difference between C++ and "immutable by design" languages is that in C++ you'd have to write your own little processor to ensure that your rule is followed (this is no big deal, and I've written much more complex processors to enforce C++ coding standards as part of the build.)
- AgentME 12y agoconst / final in most languages don't prevent the object from being mutated. They just stop the variable binding from being changed.
- zzzcpan 12y ago> I think a bigger threat is event driven code which IMHO is notorious for making things happen in unexpected order. What do you mean by unexpected order? I find event driven code to be the easiest to understand and maintain. Typically, you will be forced to specify order explicitly, i.e. nesting callbacks for sequential execution or not for parallel.
- niche 12y agoLook, I care about functional programming, I just haz no reason to use it atm Cheers!
- taeric 12y agoI can't make it past the first sentance in the opening without just wanting to scream in annoyance. Nothing about immutable objects means that you are going to write thread safe code. Pretty much period. Worse, nothing about functional programming is necessarily about immutability. It is a convenience on small and easy problems, but is far from required. Consider how your computer adds two numbers. Lots of things change state under highly timed situations to give you that answer. It is not some magic table lookup that works with immutable facts. I may just be bitter by a system right now that is using immutable objects everywhere. I realize this is a straw man, but with heavy reliance on deep (3+ levels) of immutable relationships, it is not uncommon to find crap that is the equivalent of this: String foo = "hello"; Character bar = foo.charAt(0); ... //We need to make sure bar is capitalized everywhere baz = bar.toUpperCase(); //Now to find everywhere this matters and let the caller know. I realize lenses and zippers and such can help, but so can just being a bit more disciplined about using modifiable items in the first bloody place.
- Dewie 12y ago> I can't make it past the first sentance in the opening without just wanting to scream in annoyance. Can I recommend meditation? Maybe going for a run.
- taeric 12y agoYeah, screaming is a touch heavy. I should have just said drop my head in sadness. And that I lost a little more hope from the industry. It is funny that this would lead to meditation, as there is a good parable that seems appropriate here.[1] Not all fads are processes, and I'm sure there is a "truly immutable patterns don't have this problem" hiding somewhere. [1] http://www.ckwop.me.uk/Meditation-driven-development.html http://www.ckwop.me.uk/Meditation-driven-development.html
- davexunit 12y agoYour example makes no sense to me, particularly the "find everywhere this matters" part. Working with immutable data is fairly straightforward. You perform an operation on a data structure, which produces a new version of that data structure, and then you to return it.
- brudgers 12y agoIf you do not care about mutability, you will only get immutable data. You can then send the data between different threads, and it will not get corrupted. The reason is that whenever you attempt to change them, a new instance of the structure being changed will be allocated. There is a lot to recommend a functional programming style in general and forgoing mutation of data in particular, but these are programming practices. Clojure allows mutation. Common Lisp allows it in ways that are as mind blowingly difficult to grok as macros. The shared structure that allows efficient immutability semantics allows a tsunami of value changes if someone is careless or malicious.
- wtetzner 12y agoClojure allows mutation, but the data structures that use structural sharing aren't mutable.
- skybrian 12y agoImmutability is basically like explicit version control. If the program is interactive, sooner or later you need to write a state machine that updates HEAD. A good example is the foldp function in Elm. [1] You can probably do this in any language, but efficiency is another issue. [1] http://package.elm-lang.org/packages/elm-lang/core/1.1.1/Signal#foldp http://package.elm-lang.org/packages/elm-lang/core/1.1.1/Sig...
- TheOtherHobbes 12y agoImmutability is nothing like explicit version control. So far as I know no language has anything close to explicit version control for state. This is unfortunate, because it could potentially be a very useful if every single atom of data came with a built-in list of previous states, with timestamps, and with an identifier for the code/process that last changed the state. Obviously, this is usually what debuggers try to do. But there's no reason why something like this couldn't be built into a language. (Yes, it would be slow. No, it wouldn't be that slow if done right. It wouldn't even have to be slower than many other standard practices. But yes, it could potentially use a lot of memory unless given a cutoff. Even so...) CS generally still seems stuck in the "memory is a line pigeonholes" model, and immutability seems to be a crude memory management hack, not a complete state control solution. I sometimes wonder if a lot of the issues with state are caused by the fact that languages have extremely limited tools for dealing explicitly with representations of historical causality and past/present/future, and not because state itself is inherently evil.
- cfallin 12y ago> Immutability is nothing like explicit version control. So far as I know no language has anything close to explicit version control for state. Well, it depends on which version control system we're imagining. In my mind, the immutable data-structure approach is like git, and I think what you're imagining is more like CVS. Consider: immutability by itself doesn't enforce versioning; it just makes the state-of-the-world equivalent to state-of-the-root-pointers-of-your-heap, because the pointed-to things cannot change. (I.e., referential transparency.) So it pushes the versioning up to whatever agents manage the root pointers. This is sort of like git: you build an immutable DAG, and you have mutable HEAD pointers that move around in it. (The difference is that git has one HEAD for the tree while this world has one HEAD per global or stack-local root.) When you have a reference, you have a snapshot of the world in time that will never change. Your "each slot has a list of previous states" is more like CVS in that it versions each "file" separately. This is also useful, but for a different reason: sometimes you really do want that history as a first-class concept. You can derive the per-file history in a git-like system too but it involves some computation. (And coming back from the analogy, in such a memory-management scheme, you would need to formalize the changes to root pointers into some sort of transaction system.) All of that said, I think what you describe would be really useful for debugging, albeit probably pretty expensive (each store instruction touches an undo log?). Time-reversible debuggers may have done something like this?