Hello all, first time poster, short time user here. I'm not a programmer by any stretch, so my questions are surely going to be pretty ignorant.
Ever since I picked up Pico-8, I've been approaching my programming in a functional matter because it helps me reason about my program, reuse code, and all that fancy compositional stuff that comes for free with functional design. That's not because I'm smart or anything, I just ended up learning some Haskell and now I'm used to thinking functionally.
Anyway, imperative programming is a little foreign to me, but I've always heard people insist that functional programming is inefficient. That's definitely a myth in the compiled world, but I assume that there must be some truth to it if I just go around naively composing functions together in Lua without any idea of what's going on in the metal.
Are there any good resources out there for how to use functional patterns without breaking things down the road? What drawbacks are there to passing arguments through a long chain of functions, instead of just mutating state like the cool imperative kids do? I'll come back with some of my own (ugly) code samples to be a little more specific.
Don't listen to those filthy OOers! They know not what they do!
Object oriented design has advantages and disadvantages. So does functional programming. I suppose there are probably tonnes of articles around written by people much more in the know than me debating each.
I think one of the great things about Lua is it's ability to be used for either! So you're not inherently doing anything wrong. I think it's more a case of what works better for you so you can keep the program readable while you're working on it. My gut says OO is supposed to be easier to manage on a large scale - which Pico 8 is not!
I guess there's probably piles of material like I said but I'd suggest writing a cart functionally then writing another cart with objects (possibly the same game design!) And comparing what was easier or harder in each.
I'd be curious to see your findings!
Lua is primarily an imperative programming language with a bit of support for both functional programming (anonymous functions, closures) and object oriented programming (metatables).
If you want full support for these (e.g. map/filter/reduce and more complex combinators for functional programming, full-featured classes for object-oriented), you'll usually need to either define your own helper functions or use an existing library (which isn't too practical for pico8).
Nothing stops you from defining those helpers and coding in a more functional style, but doing things as simple as possible (and perhaps simpler) is the pico8 way (and arguably the lua way as well), and that usually means imperative programming.
Write code that only you will read and maintain in whatever way you will like best.
If you're writing code others will read and maintain, write in the most typical manner found in the language you're using, because that's what most people who will touch your code will be accustomed to working in at the time, so they will be best able to read, understand, and modify your code.
Lua -> imperative, at least on PICO-8; sometimes OO
C++ -> object oriented
Haskell -> functional
- Prolog -> inside-out lunacy
Trying to write in a mode other than the usual just asks for trouble and even resentment in group environments.
But, like I said, if you're just writing for you, and for the fun of it, go nuts and do whatever you like.
I wouln't classify programming languages that easily. C++ has a lot of features, including recently lambdas, and with all the features it can you can definitely adopt a functional style if you want. With a library it should be pretty easy, with little bit of search I already found one https://github.com/GJDuck/libf
For pico the pattern I see working best is:
- have some global state, player coords, enemy list, so on, define them them at one place so you can keep track
- functions that mutate the state are updates, only called from _update
- drawing functions must not mutate the state and can only be called from _draw
- helper/function/algorithms that are stateless
You can adopt a more functional style when writing some code, for example filter function that returns new array, then you can write in one line of code to delete all enemies that are in range of a bomb or something using a lambda.
Unfortunately gamestate and drawing code is inherently imperative, you also want this to be fast and to avoid unnecessary operations and memory allocations per frame, so you can hit that juicy 60 fps constantly. A purely functional way would be to build next state from current state, but I don't see what benefit this would bring to a game, maybe a reverse time mechanic? But keep in mind that the memory is pretty limited, so you should also monitor memory usage if you are doing this type of thing.
Seems like a fun thing to do, maybe there are some advantages to it, I don't know, give it a try :)
Don't listen to the Debbie Downers. Lua is no Haskell, but it CAN do FP as well, or better, at least, than something like JS. Lua is officially a mutli-paradigm language, and has a lot of functional features like first class functions, anonymous functions, proper tail call optimization etc.
I think FP has some good ideas that your code can certainly benefit from, but I wouldn't obsess over trying to be 100% pure. Keep your state minimal, keep you functions mostly stateless, take advantage of the first class functions, like switching the value of _update and _draw instead of state flags etc. Especially if you're "not a programmer" and kind of new to the design patterns, just take what makes sense, is helpful, and fudge where it's creating more problems than it's preventing.
For resources, if you can abstract fair enough, I would recommend something like Kyle Simpson's Functional Light JS. The two languages are fairly similar, and he does a good job of going into the concepts and principles while maintaining a realistic attitude about it. Just keep in mind not to let the language specific elements get you confused.
|switching the value of _update and _draw instead of state flags etc.|
Could you elaborate on this? I'm not sure what this means or how I could look it up.
I'm just fiddling around still with finding a good way of updating my global state in a way that lets me work functionally without using too much memory (I might have stumbled on a good method but we'll see).
Log in to post a comment