4 ms·
I 100% agree with this. One of the best compliments I ever got (regarding programming) was from one of my principal engineers who said something along the line
by louthy 2y ago
I 100% agree with this. One of the best compliments I ever got (regarding programming) was from one of my principal engineers who said something along the lines of "your code reads like a story". He meant he could open a code file I had written, read from top to bottom and follow the 'narrative' in an easy way, because of how I'd ordered functions, but also how I created declarative implementations that would 'talk' to the reader.
I follow the pure functional programming paradigm which I think lends itself to this more narrative style. The functions are self contained in that their dependencies/inputs are the arguments provided or other pure functions, and the outputs are entirely in the return type.
This makes it incredibly easy to walk a reader through the complexity step-by-step (whereas other paradigms might have other complexities, like hidden state, for example). So, ironically, the most mathematically precise programming paradigm is also the best for the more narrative style (IMHO of course!)
- qwertygnu 2y ago> The functions are self contained in that their dependencies/inputs are the arguments provided or other pure functions and the outputs are entirely in the return type. Is this just a fancy way of saying static functions?
- louthy 2y agoNope, pure functions are referentially transparent. The key idea is that you can replace the function invocation with a value and it shouldn’t change the program. A regular static function could refer to a file, a database, or it could change some global memory, etc. So, replacing the static function (that causes side-effects) with a pure value wouldn’t result in the same program. Side-effects are usually declaratively represented by something like an IO monad. Which in reality is just a lambda with the side-effecting behaviour in the body of the lambda. So, to make a pure IO function you don’t actually perform the IO in the function, you return a data type (the lambda) that represents the IO to perform. This maintains the purity if the function and ‘passes the buck’ to the caller. In the case of Haskell, all the way up to its Main function and into its runtime — making the language itself pure, even if the runtime isn’t. This isn't just a Haskell thing though. I'll write code this way in C# (and have built a large pure-FP framework for C# to facilitate this approach [1]). Here's an example of the more 'narrative style' [2] of C# using pure-FP. It reads from top-to-bottom, keeping the related functions near each other and walking the reader through the functionality. There's also a massive removal of the usual clutter you see in C#/Java programs, getting down to the essence of the logic. It won't be to everybody's taste (as it's not idiomatic at all), but it demonstrates the idea. This style works well for regular program logic and less well for things like APIs where there's not always a narrative you can tell. [1] https://github.com/louthy/language-ext https://github.com/louthy/language-ext [2] https://github.com/louthy/language-ext/blob/main/Samples/CardGame/Game.cs https://github.com/louthy/language-ext/blob/main/Samples/Car...
- syklemil 2y ago> Nope, pure functions are referentially transparent. The key idea is that you can replace the function invocation with a value and it shouldn’t change the program. [Edit: This is wrong: And idempotent.] Generally you can expect that you can call them as many times as you like and get the exact same result. It _feels_ very safe. > This isn't just a Haskell thing though. I'll write code this way in C# (and have built a large pure-FP framework for C# to facilitate this approach [1]). I think that habit from Haskell is also what allowed me to pick up Rust pretty easily. You don't run afoul of the borrowchecker much if you don't expect to mutate a lot of stuff, and especially at a distance.
- chowells 2y agoThat's not what idempotent means. Idempotent means forall x, f(x)=f(f(x)). Most pure functions are not idempotent. Heck, f(f(x)) doesn't even type-check for most f. The typical name given to always getting the same results is just "pure". It doesn't depend on any implicit state anywhere.
- syklemil 2y agoRight you are. I wish I had an excuse for my mistake, but I don't.
- hinkley 2y agoThere’s a difference between simplifying a concept and stating it plainly. I use this analogy a lot. Code can be like a novel, a short story, or a poem. A short story has to get to the point pretty quickly. A poem has to be even more so, but it relies either on shared context or extensive unpacking to be understood. It’s beautiful but not functional. And there are a bunch of us short story writers who just want to get to the fucking point with a little bit of artistic flair, surrounded by a bunch of loud novel and mystery writers arguing with the loudest poets over which is right when they are both wrong. And then there’s that asshole over there writing haikus all the fucking time and expecting the rest of us to be impressed. The poets are rightfully intimidated but nobody else wants to deal with his bullshit.
- h4ny 2y agoI see where you are coming from but that's unnecessarily hostile. > There’s a difference between simplifying a concept and stating it plainly. You are right, but they are not mutually exclusive. The analogy you used with novel, short story, and poem/haiku also doesn't demonstrate your point: it's not like you can compress any novel into a short story, let alone a poem. If you're into games, try equating AAA-quality 3D games to novel, high-resolution 2D games to short stories, and pixel art games to haikus: it doesn't make sense and it's ridiculous. I respect that you are passionate about the medium you choose, but what you claimed about novels and poems, as per your own words, "they are both wrong" at best. Don't generalize your personal experience to everyone else, there are kind, hardworking people out there writing novels and poems who love short stories just as much -- maybe what you need to do is to find those people instead of spewing your unwarranted anger over them.
- hinkley 2y agoIf you think people only get upset about things for their own self interest, then I wonder what you think about social justice. You have a Texas Sharpshooter Fallacy in your logic. A novelist is successful if they reach an audience. Once they find it, if they stick with it they will be successful. If they’re lucky then they might switch up genres without alienating their existing readers. But not everyone gets away with that. A software developer has one audience and they don’t get to chose it. You and I write for our coworkers. If they don’t like it we have three choices. We can leave, we can change, or we can gaslight our coworkers that our code is just fine and they are the problem. It’s the latter I’ve seen too much of, and even if you’re not a victim of it you’re allowed to be incensed for those who are. In fact you’re obligated to do so.
- DidYaWipe 2y agoI had a similar experience. I was a lead on a project where the client sent a functional expert to literally (at times) watch over my shoulder as I worked. He got very frustrated after a few weeks, seeing little in the way of code being laid down. He even complained to the project manager. That's because this was a complicated manufacturing system, and I was absorbing the necessary rules for it and designing it... a process that involved mostly sitting and thinking. When I decided on the final design and basically barfed all the code out in a matter of days, I walked this guy (a non-programmer) through the code. He then wrote my manager a letter declaring it to be the "most beautiful code he had ever seen." I still have the Post-It she left in my cube telling me that. I have little tolerance for untidy code, and also overly-clever syntax that wastes the reader's time trying to unravel it. And now we have languages building more inconsistent and obscure syntax in as special-case options, wasting more time. Specifically I'm thinking about Swift; where, if the last parameter in a function call is a closure, it's a "trailing" closure and you can just ignore the function signature and plop the whole closure right there AFTER the closing parenthesis. Why?https://www.hackingwithswift.com/sixty/6/5/trailing-closure-syntax https://www.hackingwithswift.com/sixty/6/5/trailing-closure-... This is just one example, and yeah... you can get used to it. But in this example, the language has undermined PARENTHESES, a notation that is almost universally understood to enclose things. When something that basic is out the window, you're dealing with language designers who lack an appreciation for human communication.