Applicability of FP unchanging things to real world changing things

I come from an OO background, but have recently started to see the light and think that functional programming has a lot to offer in real world, general software development - not just some small specific niche. Having the OO background certainly has limited the way I view software development, and I guess in learning something new, I have a tendency to compare it with what I do know, looking for similarities and differences. So, perhaps that's why I am having difficulty in seeing how some functional programming ideas apply. What's got me a little puzzled at the moment is non mutable data. On the one hand, I think it's great that I can mostly forget about errors caused by my variables having unexpected values, and that I can reason about my program much more easily... However, on the other hand, I wonder how it ties in with real world systems that do in fact do deal with objects that change state. For example, if I was building a library system - I might have book objects, and if a book gets borrowed, there remains the same book object, but it now just has a different state - from "on shelf" say, to "borrowed". Now, in Haskell, I might have a function to lend a book :- lend book1 and this is going to return a new book, with the appropriate status change.. ..but what of the old book ? I don't want 2 book objects floating around.. ...to my way of thinking, it's really not a new book, it really is a change of state. How do people see this kind of situation ? Is it just the way of looking at it... ? Do I just accept that I toss out my old library object, and have a new one, which happens to be the same as the old one, except for the "new" book which is now borrowed ? Do I really need to get over thinking of objects in the first place, even though it's what I see exist in the real world ? Is there where we part company with non mutability and venture into the monads where we do have side effects ? Any thoughts appreciated ! :) Thanks !

Computers think discretely. Even the OO book is probably not going to recognize the book's every move as it falls into someone's hands, wanders around the library, perhaps sneaks out of the library or is reshelved somewhere else, is checked out and goes across the globe, has the cover torn and then taped together into pretty-good shape... I prefer FP because it acknowledges that computers fundamentally operate like this. They model and approximate situations. Sometimes pretending to be those situations is not the best way to approximate them. ...[tried to give example but I'm too dizzy at the moment from finals-week]

On Sun, Dec 13, 2009 at 02:11:28AM +0000, Glurk wrote:
What's got me a little puzzled at the moment is non mutable data. [...] How do people see this kind of situation ? Is it just the way of looking at it... ? Do I just accept that I toss out my old library object, and have a new one, which happens to be the same as the old one, except for the "new" book which is now borrowed ?
Do I really need to get over thinking of objects in the first place, even though it's what I see exist in the real world ?
Mutability perhaps more directly matches how we look at the world, in which objects have states that change over time. Purely functional programming doesn't allow mutating data in place, so we have the "evolution" of an object through time. We get multiple snapshots. I like to think of it as having 1 dimensional objects instead of having 0 dimensional objects, in direct analogy to thinking of objects in the world as being 4 dimensional: 3 spatial and 1 time dimension. Rich Hickey (the Clojure guy) gave a keynote talk about this kind of thing: http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey Here's an interview about the same thing: http://www.artima.com/articles/hickey_on_time.html I've only watched the keynote, which I found really interesting. Maybe these will better help you get a grasp on a "functional" way of thinking? Hope that helps, John

Glurk wrote:
So, perhaps that's why I am having difficulty in seeing how some functional programming ideas apply.
What's got me a little puzzled at the moment is non mutable data. On the one hand, I think it's great that I can mostly forget about errors caused by my variables having unexpected values, and that I can reason about my program much more easily...
However, on the other hand, I wonder how it ties in with real world systems that do in fact do deal with objects that change state.
For example, if I was building a library system - I might have book objects, and if a book gets borrowed, there remains the same book object, but it now just has a different state - from "on shelf" say, to "borrowed".
Now, in Haskell, I might have a function to lend a book :-
lend book1
and this is going to return a new book, with the appropriate status change.. ...but what of the old book ? I don't want 2 book objects floating around.. ....to my way of thinking, it's really not a new book, it really is a change of state.
How do people see this kind of situation ? Is it just the way of looking at it... ? Do I just accept that I toss out my old library object, and have a new one, which happens to be the same as the old one, except for the "new" book which is now borrowed ?
Do I really need to get over thinking of objects in the first place, even though it's what I see exist in the real world ?
The point is that the real world doesn't happen inside the computer, only a model of it. The functional paradigm is based on the idea that immutable variables make for great models, even when state changes are involved. In other words, the book in your example is not a real book, it's just a few bytes in the computer that model it for the purpose of tracking whether it's lent out or not. For instance, these few bytes can be a unique ID and a possible lend function is lend :: BookID -> Library -> Library where the data type Library is a giant table of book IDs that keeps track of which ones are lent out and which are not. Together with a notion of "the current library", this is enough to model your example. In the end, even the library example is somewhat special in that it's too much about reality. Most programming problems, like sorting, compressing, type inference, etc. etc. are more abstract in nature and there is no a priori reason why mutable variables would be a good way of describing and modeling them. In fact, physics has been very successful at modeling the real world without mutable variables for centuries. Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

On Sun, Dec 13, 2009 at 11:24:06AM +0100, Heinrich Apfelmus wrote:
In other words, the book in your example is not a real book, it's just a few bytes in the computer that model it for the purpose of tracking whether it's lent out or not. For instance, these few bytes can be a unique ID and a possible lend function is
lend :: BookID -> Library -> Library
I should also point out that people coming from an OO or imperative background often look at a function like this and think it looks incredibly inefficient --- why throw away the entire *library* and build a new one *from scratch* when all we want to do is modify one little part of it? This seems a huge price to pay for immutability! But this line of thinking confuses abstract semantics with concrete implementation (something that imperative programming unfortunately tends to encourage, in my experience). The runtime is free to implement operations like "lend" any way it likes, as long as the abstract semantics are preserved. In this particular example, most of the "new" Library will probably be shared with the "old" Library, and just the part that is changed needs to be updated (in fact, note that this is only possible because Library is immutable! =) So in terms of actual execution we get the same efficiency that we would have by mutating the Library, but we get the cognitive benefit of being able to *think* of it as if we have produced an entirely new Library. -Brent

On Sun, Dec 13, 2009 at 6:21 PM, Brent Yorgey
On Sun, Dec 13, 2009 at 11:24:06AM +0100, Heinrich Apfelmus wrote:
In other words, the book in your example is not a real book, it's just a few bytes in the computer that model it for the purpose of tracking whether it's lent out or not. For instance, these few bytes can be a unique ID and a possible lend function is
lend :: BookID -> Library -> Library
I should also point out that people coming from an OO or imperative background often look at a function like this and think it looks incredibly inefficient --- why throw away the entire *library* and build a new one *from scratch* when all we want to do is modify one little part of it? This seems a huge price to pay for immutability!
But this line of thinking confuses abstract semantics with concrete implementation (something that imperative programming unfortunately tends to encourage, in my experience). The runtime is free to implement operations like "lend" any way it likes, as long as the abstract semantics are preserved. In this particular example, most of the "new" Library will probably be shared with the "old" Library, and just the part that is changed needs to be updated (in fact, note that this is only possible because Library is immutable! =) So in terms of actual execution we get the same efficiency that we would have by mutating the Library, but we get the cognitive benefit of being able to *think* of it as if we have produced an entirely new Library.
Doesn't this immutability make some things very easy to implement? For instance, it ought to be trivial to backup state to disk (for recovery or rollback), one just hands it to a thread asynchronously and then continues handling requests. Doing that sort of thing with mutable state requires a bit more work, I'd say.
From watching a presentation on Happstack, I believe this is how it achieves some of its nice features.
/M -- Magnus Therning (OpenPGP: 0xAB4DFBA4) magnus@therning.org Jabber: magnus@therning.org http://therning.org/magnus identi.ca|twitter: magthe

On Sun, Dec 13, 2009 at 12:21 PM, Brent Yorgey
On Sun, Dec 13, 2009 at 11:24:06AM +0100, Heinrich Apfelmus wrote:
In other words, the book in your example is not a real book, it's just a few bytes in the computer that model it for the purpose of tracking whether it's lent out or not. For instance, these few bytes can be a unique ID and a possible lend function is
lend :: BookID -> Library -> Library
I should also point out that people coming from an OO or imperative background often look at a function like this and think it looks incredibly inefficient --- why throw away the entire *library* and build a new one *from scratch* when all we want to do is modify one little part of it? This seems a huge price to pay for immutability!
But this line of thinking confuses abstract semantics with concrete implementation (something that imperative programming unfortunately tends to encourage, in my experience). The runtime is free to implement operations like "lend" any way it likes, as long as the abstract semantics are preserved.
+1 One of the turning points in learning the FP way is the realization that the conception of "function" as a "machine" or "transformation process" is misleading or even harmful. For most programmers coming from an imperative language background that's going to mean returning to a more mathematically pure notion of function, which means discarding the idea of mutating parts of an object in favor of establishing relations among different "objects" and letting the compiler worry about the gory details. Youschkevitch's fascinating history of the concepthttp://www.springerlink.com/content/p3x21230u404p13h/might be useful. -gregg

On Monday 14 December 2009 09:54:53 am Gregg Reynolds wrote:
Youschkevitch's fascinating history of the concept http://www.springerlink.com/content/p3x21230u404p13h/ might be useful.
Too bad it's paywalled :-( Shawn.

Glurk wrote:
However, on the other hand, I wonder how it ties in with real world systems that do in fact do deal with objects that change state.
Do they change state? Or do you see a new object with a different state than the previous object? Can you step into the same river twice?
For example, if I was building a library system - I might have book objects, and if a book gets borrowed, there remains the same book object, but it now just has a different state - from "on shelf" say, to "borrowed".
Now, in Haskell, I might have a function to lend a book :-
lend book1
and this is going to return a new book, with the appropriate status change.. ..but what of the old book ? I don't want 2 book objects floating around.. ...to my way of thinking, it's really not a new book, it really is a change of state.
How do people see this kind of situation ? Is it just the way of looking at it... ? Do I just accept that I toss out my old library object, and have a new one, which happens to be the same as the old one, except for the "new" book which is now borrowed ?
Do I really need to get over thinking of objects in the first place, even though it's what I see exist in the real world ?
As Master Apfelmus has written, what you see (or what you think you see, if that is different) is almost completely irrelevant to what is going on in your program in the computer. If you lend a book, the book doesn't change. The library doesn't change. What changes is a model of the library, which now indicates that a book is lent to someone, and the real question is how best to build that model of the library. Most object oriented languages are inherently procedural; this is equivalent to writing all of your code in the IO monad. Haskell gives you more options than that, including writing pure functional code with the type lend :: Book -> Library -> Library which has all sorts of neat properties that help you build the model without falling into some of the potholes that go along with procedural programming.
Is there where we part company with non mutability and venture into the monads where we do have side effects ?
At some point, you will ask, "What about these two Libraries floating around?" and realize that what you really need is a monad and ideally one specific to your Library (rather than the general IO monad). Then you will be enlightened. -- Tommy "Gotta cut down on the cold meds" McGuire mcguire@crsr.net

I agree with the points some people have raised - as I said in the original post, I certainly like some of the things that FP gives me.
Do they change state? Or do you see a new object with a different state than the previous object? Can you step into the same river twice?
I think a lot of people, looking at the real world, would answer, yes, it clearly IS the same book, now in a different state. And yes, I CAN step into the same river twice. This is how people see and think about the real world. So, while I understand and like the benefits that thinking of things as mathematical concepts gives me, it seems to me that it does take your program further away from the real word, and thus can make it less understandable because of this. There is a certain adavantage in having a close mapping from the real world to your program - if your program is meant to be dealing with real world things.
As Master Apfelmus has written, what you see (or what you think you see, if that is different) is almost completely irrelevant to what is going on in your program in the computer. If you lend a book, the book doesn't change. The library doesn't change. What changes is a model of the library, which now indicates that a book is lent to someone, and the real question is how best to build that model of the library.
I agree with you, that yes, it's our model that we're really working with, not the real world, and that the question is how best to build the model. However, in answering that question, as I said, I think that there are some advantages in there being a close relationship between the real world, and our model - in terms of understandability, which, personally, I believe is one of the most important things in any system. So, I'm not sure I agree that what we see in the real world is "almost completely irrelevant". If the mapping from real world to program is hard to understand, then it can make it harder to maintain. To make a farfetched example, if we model our book as an apple, and each time it is lent a bite gets taken out of it...... well..that's just completely ridiculous, right ? It's ridiculous because what we see in the real world IS important to how we model. It certainly doesn't mean that we have to model things exactly as we see them - obviously, we drop things we think are irrelevant etc ...but, I think in generaly, it CAN make visualization and understanding easier, if our model has a certain similarity to the thing it is modelling ! So, I'm just thinking that in the real world, we typically do think of changing objects, so a model which also has this property, can help in understanding. Of course, if we train ourselves to think differently...then a model containing immutable objects might have more benefits than drawbacks - and I think that's what most FP supporters are claiming.
At some point, you will ask, "What about these two Libraries floating around?" and realize that what you really need is a monad and ideally one specific to your Library (rather than the general IO monad). Then you will be enlightened.
I guess that brings up another point - that eventually we are drawn into monads, which to me seems a bit unfortunate, because it seems that it leads us back to imperative programming with mutable state... As someone else suggested, perhaps FRP is an answer here.. ..I must admit I don't understand much about that, I'll look into it a bit more ! Glurk

2009/12/15 Glurk
So, I'm just thinking that in the real world, we typically do think of changing objects, so a model which also has this property, can help in understanding.
Ah but Glurk, a model that has this property can often greatly _hinder_ understanding: Its well know in OO circles that state change is problematic for 'modelling' - vis the damage done to a circle or square object by the otherwise standard operation of a non-uniform scale, where the circle is obliged to become an ellipse, the square an oblong. [1] Typestate object oriented languages exist where one can migrate e.g a closed file object into an open file and back again, but are somewhat off the beaten path, seemingly doomed to be curios every once in a while at POPL, OOPSLA... Best wishes Stephen [1] http://en.wikipedia.org/wiki/Circle-ellipse_problem [2] http://www.cs.cmu.edu/~aldrich/papers/onward2009-state.pdf
participants (10)
-
Brent Yorgey
-
Glurk
-
Gregg Reynolds
-
Heinrich Apfelmus
-
Isaac Dupree
-
John Li
-
Magnus Therning
-
Shawn Willden
-
Stephen Tetley
-
Tommy M. McGuire