> As long as the functions are named well and communicate (only) with params and return values, it doesn't hurt readability to split it up, even if it's only used in one place.
It's interesting how even in the context of C the virtues that functional programming dials up to eleves come up.
(Git is similar: it's a dirty C program with lots of mutation under the hood, but when you use it you can sort-of pretend it purely functional, since the main things you care about are append-only, and even rewriting history just creates a new slightly altered copy of history, and the old one is available until the GC kicks in. Similar for the recent craze of copy-on-write in filesystems.)
Yes it's it's a common pattern, especially in distributed systems. What concern does functional programming share with distributed systems? Being disciplined about state. A distributed system is no longer a Von Neumann machine, because you don't have globally consistent state (without paying for it). Procedural languages assume you're using the Von Neumann model.
Also, what does OOP share with functional programming? Being disciplined about state. When OOP is used well, you're protecting invariants on state inside classes.
Basically the anti-pattern is global mutable state, which most (old) codebases still have. It works poorly for concurrency too (e.g. Python and the GIL).
Here are a couple related comments which touch on OOP and FP, which a lot of people seemed to like:
https://news.ycombinator.com/item?id=11841893 -- there's no real advantage to expressing something like "split a string by a delimiter" in a purely functional style. Either way, you have a trivial referentially transparent function you can reuse without causing complexity in your program. You might as well do the obvious imperative thing.
Also, I neglected to mention that this style actually doesn't work all that well in C. It works better in C++.
Not only because C++ has classes and C doesn't, but because of char. I was recently hacking on the Python interpreter, and wondering about functions like Py_SetPath(char ) and setenv(char, char) (from libc). The problem is that I have no idea whether those functions copy their arguments or they store pointers to them. I had to go read three levels deep.
So in that sense, functions in C fail miserably... they are not functions in the mathematical sense, so you can't reason about them the same way without strong conventions.
> So in that sense, functions in C fail miserably... they are not functions in the mathematical sense, so you can't reason about them the same way without strong conventions.
Yes. Hence my astonishment and use of "even in C".
Indeed, the most important bit for functional programming in the large are well-defined interfaces and a very disciplined use of state. In the languages I use I see no need to resort to imperative features for "split a string by a delimiter"---but if your language is a bit clunky that might be the path of least resistance.
(To give a counterexample to my point, even in Haskell you might want to use eg a mutable hashtable in an imperative fashion. Even if that means going out of your way to do so.)
Avoiding global (or singleton) state is only the start of what's necessary. Even then OO programs tends to have lots of little pockets of state whose network of interactions goes to a large scale again and doesn't compose well.
It's interesting how even in the context of C the virtues that functional programming dials up to eleves come up.
(Git is similar: it's a dirty C program with lots of mutation under the hood, but when you use it you can sort-of pretend it purely functional, since the main things you care about are append-only, and even rewriting history just creates a new slightly altered copy of history, and the old one is available until the GC kicks in. Similar for the recent craze of copy-on-write in filesystems.)