Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

To me, the future will most likely be languages that allows both functional and OO styles to interoperate. Programmers will pick the style or mix of styles most appropriate to the particular sub-problem they're solving.

We already do this with some of our high-level languages like Ruby and JavaScript. With these, we have higher-order functions, map and friends, closures, etc.. But we also have our familiar OO constructs. Almost every program I write in these languages uses all of the above, not just the functional or OO subset.

I so far have not seen any practical advantage in going purely functional. I've tried it a number of times, but I always find that the real-world programs I write need to be stateful. Yes, functional languages do of course have facilities for handling state, but they always seem super awkward, especially compared to the elegance of state handling in OOP.

For example, consider a simple, 1980s-style arcade game. There are a bunch of entities on screen, each with attributes like velocity, health, etc.. How do you maintain this state in a purely functional language? I've seen various suggestions, but they all seem to boil down to setting up a game loop with tail recursion, and then passing some game state object(s) to this function on each recursion. Doesn't sound so bad, but what happens when you have a bunch of different types of entities? E.g. player characters, monsters, projectiles, pickups, etc..

Well, every time you add a new type of entity (or a new data structure to index existing entities), you could add another parameter to the main game loop. But that gets crazy pretty fast. So then you have the clever idea to maintain one massive game state hash, and just pass that around. But wait, now you've lost something key to functional programming: You can no longer tell exactly what aspects of the game state a function is updating, because it just receives and returns the big game state hash. You don't really know what data your functions depend on our modify. Effectively, it's almost like you're using global variables.

I'm using games as an example here, but the same sorts of problems come up with almost any stateful application.

This is why I prefer languages that allow you to seamlessly mix functional and OO styles. They give you many of the benefits of FP without forcing you to deal with the difficulties described above.



For games and other reactive systems, you should check out functional reactive programming (FRP)[1]. The basic idea is to model time explicitly, working with time-varying values. So you would express your game logic as a network of event streams and signals.

[1]: http://stackoverflow.com/questions/1028250/what-is-functiona...

This is a radically different from the normal imperative approach, and I've found it to be much nicer. Admittedly, I haven't tried making games per se, but I have used it successfully for several other interactive UI programs.

FRP is a good approach for any system where you would normally use events and callbacks. This includes UIs and games as well as things like controllers or even music. So at least for that sort of IO-heavy and stateful domains, there is a very good declarative approach.


FRP is super nice, but no magic. I found that it makes it natural to decompose the codebase in model/view/controller and encourages an explicit state machine for updating the model. At the same time, a time-varying value is a plain old observable. But the discipline enforced by FRP avoids the spagetti trap most event-based systems eventually fall into. No magic, therefore useable my mere mortals :)


Now that is really cool. You've convinced me that this could be a viable and practical approach to handling highly stageful programs in an FP context.

One question though: Does memory/storage become an issue if you're keeping track of values "over time?" If I understand it correctly, you'd have a constantly growing picture of your data as it has evolved, with a complete history of prior values. (Maybe I'm wrong about this part, though.) For applications that are long-running or handle a lot of data, could this be a fatal problem?


You're not necessarily keeping track of all the old values over time. Rather, the core idea is that you program in terms of abstractions that are explicit about time. That is, you write your program in terms of streams of events or signals.

You have signals and events, but you never ask about the value right now; instead, you take these two abstractions and combine them in different ways to get a reactive network. In a way, it's similar to dataflow programming or circuit design: you connect up "wires" into a network that can constantly push through data. Depending on how you write this network, you will need to remember different amounts of past data at runtime.

If you write your event/signal network carefully, you do not need to keep a history of too many prior values at runtime. This is one of the things modern FRP libraries really try to help you with: writing networks that are efficient. At least the ones I've tried are good at this--I haven't had many space problems in my programs so far.

In summary, this is a potential issue, and you may have to be a little careful in how you write your FRP code. However, modern frameworks try to make it easy to avoid these pitfalls, and there is no fundamental reason you can't use memory efficiently with this model.


I'm pretty new to FRP, but I tend to visualize FRP like an Excel spreadsheet where one value change leads to a chain reaction of many values in the spreadsheet.

Would this paint the right picture?


Very well. In fact, one of very first implementations I've ever heard of was done in Lisp and it was described exactly in this way. I think the library is even called "Cells".


For an example of making Pong using FRP, check out this: http://elm-lang.org/blog/games-in-elm/part-0/Making-Pong.htm...

It's not a very long read, and it will help make FRP more concrete with a practical example.


Well, if the game state is so small, then it's quite easy to combine all these functions together in FRP style.

How about big games though? for example, World Of Warcraft or Eve Online. The game states of these are humongous, and the game state's data constructor would be huge.


> Well, every time you add a new type of entity (or a new data structure to index existing entities), you could add another parameter to the main game loop. But that gets crazy pretty fast. So then you have the clever idea to maintain one massive game state hash, and just pass that around. But wait, now you've lost something key to functional programming: You can no longer tell exactly what aspects of the game state a function is updating, because it just receives and returns the big game state hash. You don't really know what data your functions depend on our modify. Effectively, it's almost like you're using global variables.

You have to explain how that works. By "hash", do you mean a finite map (or dict, in Python terms)?

In Haskell you can use a state monad for these game loops. Some game industry insiders (see http://lambda-the-ultimate.org/node/1277) argue explicitly for this style.


A state monad is a decoration of functions that take and return the state. It's certainly prettier, and there are respects in which the parent's complaints are overblown (certainly, it's no worse than imperative languages), but the parent is entirely accurate that a function like

    frobnicateTurboencabulator :: GameState -> GameState
doesn't have a type that tells you anything about what it actually does. Compare that with something like

    on :: (b -> b -> c) -> (a -> b) -> a -> a -> c
where the type tells you basically exactly what the function does.

The state monad doesn't help with this problem:

    frobnicateTurboencabulator :: State GameState ()

Of course, the solution is is some combination of:

1) Split functionality into many typeclasses and hide the State monad, so you can see what functionality is accessed by a function (as mentioned in my other comment),

2) Have functions return a description of updates to the world-state instead of performing those updates themselves (so you know what kinds of things a particular function might do). This might have the benefit of letting you compose actions before applying them, which could in some cases be faster if the updates are likely to be large.

There are likely other options, as well.


> Of course, the solution is is some combination of:

And as always in Haskell: more type trickery. Like lenses, which help with the splitting. Applicative functors might help with "Have functions return a description of updates to the world-state [...]" for free in a sense similar to http://gergo.erdi.hu/blog/2012-12-01-static_analysis_with_ap...


Lenses are awesome, and can help with pulling data out of a WorldState object and updating it thereafter. They do not do a thing about loss of information in the function signature.


You hit the nail on the head with regarding to pure functional style. What I usually find useful it to use OO at high level, macro level, structural level to organize the code, and to use functional style at the lower level to build reusable functions. The lower level basic pure functions form the building blocks that can be reused in different circumstances since they are stateless. The domain specific and state specific aspects are left to OO to abstract and organize.


If you mix FP and OO you'll often end up with terrible FP which simply reproduces the "old" approach: lots of mutable stuff everywhere. Many Clojure toy games are like that: they start with a lot of "variables" in mutable refs.

But it doesn't need to be that bad: you can create a game that is fully deterministic. A game which is purely a function of its inputs. And it can of course be applied to more than games.

The problem is that it feels "weird" to non-FP people.

The state monad is definitely what you're looking for. If you use a state monad approx. 95% of what you just wrote is utter rubbish.

But the state monad (and the maybe monad) sadly aren't that trivial to understand.


> If you mix FP and OO you'll often end up with terrible FP which simply reproduces the "old" approach: lots of mutable stuff everywhere.

What I'm suggesting is that mutable state isn't inherently bad. It's entirely possible that we will someday enter a new age of mainstream, pure FP where we look back at mutable state and cringe. But that's pure speculation. Our current world is full of successful applications written in languages built on mutable state.

So I'm not saying that mutable state is inherently better than the alternatives. Just that the case against it--and for the alternatives--has to be pretty darn compelling to outweigh the tremendous real-world success of languages like Ruby, Python, JavaScript, and so on.


I wouldn't call what you've written a straw-man argument, but neither is it a steel-man...

My biggest takeaway, and an entirely legitimate criticism, is that if all your functions become instead State World (), your type signature no longer gives you much information about what the function does. In light of this I intend, when/if I get around to playing with a game in Haskell (or anything else that involves shipping around a huge wad of state), to look into splitting types of game state changes into multiple typeclasses, so as to see about preserving some more information about what various state transformations touch (both reading and writing)...


The maybe monad has a counterpart from the OO world: the null object pattern. They're not implemented the same way, but they serve the same purpose.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: