Iterative Functional Reactive Programming With The Nu Game Engine
Iterative Functional Reactive Programming With The Nu Game Engine
NOTE: This is an entirely informal paper, originally targeted for a simple post on a forum of
http://lambda-the-ultimate.org, but due to my inability to achieve a readable formatting with the tools
of said forum, is made available via this PDF.
2) Raw performance is good, but is not, in will never likely be, best in class. Lets face the fact that
many game programmers are speed addicts, and while their endless thirst may never be
satisfied, the engine has low-level imperative optimizations that make it more than fast enough
when used with care.
3) Verbosity is an issue also due to the indirect nature of accessing simulant properties / fields. As
mentioned above, one cannot access simulant fields with a simple property access expression,
but must be accessed by calling a function that takes a world value as a parameter. Dually,
outside of the Chain monad (which will be discussed later), the world value must be manually
thread through most engine operations.
Neither of these is a big deal, but they might be off-putting people accustomed to the
expedience of imperative programming.
Despite these minuses, I currently conclude IFRP is appropriate for such a general-purpose game engine
because
1) From my experience, games, and game technology in general, refuse to conform to any single
system of thought, often demanding certain features be implemented with escape-hatch
approaches like encapsulated mutation in order to be efficient, or with lower-level forms of
functional expression for flexibility.
2) Just because the default means of expression is not as abstract as that of FO/HOFRP systems, it
does not mean there are no available ways to 'climb into' more abstract forms of expression.
To expand on point 2, here are some of the higher forms of expression provided by the API Here we have an expression form called an 'observation' that allows combinations and transformations
of events like so let observation =
Simulants.Gameplay |>
observe (Events.Click ->- Simulants.HudHalt) |>
sum Events.Update |>
until (Events.Deselect ->- Simulants.Gameplay)
let observation = character |> observe Events.Update |> until (Events.Deselect ->- Simulants.Gameplay)
runAssumingCascade chain observation world |> snd
Finally, there is a means to declaratively forward the changing value of a simulant's field to that of
another let world =
world |>
(bob, bob.GetVisible) *-> (jim, jim.SetVisible) |>
(jim, jim.GetVisible) /-> (bob, not >> bob.SetVisible)
Here, *-> denotes the forwarding of the value of Bob's Visible field to Jim's Visible field. To throw a
monkey-wrench into the declaration, /-> is used to in turn forward the value of Jim's Visible field back to
Bob's Visible field, albeit not'd and with cycle-breaking so that the circularity of this expression is broken
appropriately. This is a contrived example, but illustrative of the API's expressiveness.
So, depending on the nature of the game behavior you want to implement, the API provides enough
surface area to do things at different points on a spectrum of flexibility and abstraction. But there is a
down-side to an API with such a larger surface area... With multiple expression forms and levels of
abstractions at which to operate, the learning curve can be steepened. Additionally, imperative
programmers may be bothered by the performance compromises implied by pure functional
programming compared to doing everything in-place, even if performance is more than satisfactory for
most games.
Compared to the more declarative FRP styles, I believe that this iterative approach of FRP is inherently
more complete, understandable, scalable, and flexible than the more declarative FRP models (FirstOrder, Higher-Order, Arrowized), and that these properties of completeness, understandability, et al,
are the minimum necessary for developing commercial games. And as to how this approach compares
to imperative / OOP style of game development I can only hope that this approach, or at least some
other functional approach, will eventually come to replace the current methods. Game development
has, in my mind, grown far too complex to make current approaches satisfactory.