Functional programming for a "jobbing programmer"



  • This is my take on what functional programming really is, in a way that will make sense to a jobbing programmer just trying to Get Stuff Done.

    Excellent pair of articles. The guy explains the ideas behind functional programming in a pragmatic manner, instead of the dogma-filled academic circlejerk you usually get.


  • :belt_onion:

    functional programming is about writing pure functions

    Is that all? He rambles all along and comes to this?



  • [code]
    public Program getCurrentProgram(TVGuide guide, int channel) {
    Schedule schedule = guide.getSchedule(channel);
    Program current = schedule.programAt(new Date());
    return current;
    }
    [/code]

    This function has a hidden input of the current time (new Date()).

    I wouldn't consider the input to be hidden if it's in the name of the function.



  • This function has a hidden input of the current time (new Date()). We can surface this complexity by just being honest about this extra input:

    public Program getProgramAt(TVGuide guide, int channel, Date when) {
      Schedule schedule = guide.getSchedule(channel);
      Program program = schedule.programAt(when);
      return program;
    }
    
    >[...]
    It isn't more complex. Hiding a dependency didn't make it simpler, being honest about it doesn't make it more complex.
    
    It *is* more complex from the point of view of the caller. Now I have to call `new Date()` myself when previously the function did it for me.
    
    With side effects, I could just tell a function to do something arbitrarily complex for me, now instead I have to know exactly what resources the function needs to do it and obtain/create them myself.


  • I still have no idea why I should care, except that it's "pure" to do so. If it was supposed to be a marketing spiel for FP for an Average Joe programmer, it doesn't really work that well.



  • @julmu said:

    This function has a hidden input of the current time (new Date()).

    I wouldn't consider the input to be hidden if it's in the name of the function.

    That's a weak kind of guarantee. Also it doesn't help you with the problem of "what happens on February 29 of a leap year"?

    I've seen many attempts to deal with "inner time" problem. Providing time as an argument is generally cleaner than just grabbing whatever is in the system clock. It's also more annoying, though.

    @Maciejasjmj said:

    I still have no idea why I should care, except that it's "pure" to do so.

    Why should you care about OOP or any pattern at all? Just write a bunch of global functions like in QBasic days and be done with it.



  • @julmu said:

    I wouldn't consider the input to be hidden if it's in the name of the function.

    I really like the term "side cause." I'd never really thought of quite that clearly before. But as he goes into in the second article, OOP pretty much guarantees some implicit side causes in a similar way to what you're talking about here. I get your point, but I also agree with him that it's more functional with the date as an explicit input (and I think we've all probably done stuff like that for reasons he's stated).

    But then...back to OOP...if this is explicitly in the call, foo.frobnicate( bar ), then I would argue that it's just syntactic sugar and not a side cause. Of course, inside an object, calls to other methods requires us to do some additional gymnastics to include this as not a side cause.

    I'm also interested to see what blakey has to say about this article after previous rants about pure functional stuff.



  • @Maciejasjmj said:

    I still have no idea why I should care, except that it's "pure" to do so.

    The reason is that things are more explicit and easier to understand from the outside. You're less likely to miss some gotcha because something unexpected happens.

    EDIT: In fact, read the Haskell section on the second article:

    The signature tells us that this version of formatName involves database-related side-effects. What the hell? Why does formatName need the database? You mean I'm going to need to set-up and mock-out a database just to test a name-formatter? That's really weird.

    Just by looking at this function signature, I can see something's wrong with the design. I don't need to look at the code, I can smell a rat just from the overview. That's magic.
    ...
    Haskell's type signatures, in contrast, tell you a great deal about the design. And because they're checked by the compiler, they tell you things you know to be true.


  • Winner of the 2016 Presidential Election

    Side-effects aren't about "hiding implementation details" - they're about hiding the code's relationship with the outside world.

    I think he fails to explain why that's necessarily a bad thing.

    I think I understand the benefits of a functional programming language. They prevent you from shooting yourself in the foot with unexpected side-effects. But in large applications, the "bad" practices that a functional programming language disallows might be exactly what you need to hide complexity and build nice, clean APIs for other submodules. Also, static code analysis tools can help you detect particularly bad practices that you might want to disallow (hidden dependencies, for example).

    Maybe writing large, modular applications is also possible in functional programming languages and I'd just have get used to a different style of programming. But I suspect that managing complexity may be a lot harder in a pure functional language, and so far nobody has managed to convince me of the opposite.


  • I survived the hour long Uno hand

    It honestly boggles my mind how... black-and-white and dogmatic people get about programming. "OOP is a waste of time!" "Functional programming doesn't make a clean API so it's never useful!"

    What ever happened to having a box of tools and using the one that makes the most sense for your problem space?



  • @asdf said:

    Maybe writing large, modular applications is also possible in functional programming languages and I'd just have get used to a different style of programming. But I suspect that managing complexity may be a lot harder in a pure functional language, and so far nobody has managed to convince me of the opposite.

    Exactly.

    That's why I like his post.

    It's not about fundamentalism. He's not trying to convince me functional code is "beautiful". "Duuude it's like words forming sentences, pure expression of thought. Radical!"

    All he's saying is, "look, if you can achieve this kind of clarity in parts of your code, it can make your life much easier down the road."

    At least that's what I got out of it. Also, where my thinking has been gravitating towards lately.



  • @Yamikuronue said:

    What ever happened to having a box of tools and using the one that makes the most sense for your problem space?

    Not as much scope for being able to tell people they're wrong on the Internet.


  • Winner of the 2016 Presidential Election

    @Yamikuronue said:

    What ever happened to having a box of tools and using the one that makes the most sense for your problem space?

    I think functional programming languages are rarely the right tool for a job, because they disallow side-effects altogether. That's pretty

    @Yamikuronue said:

    dogmatic

    in itself.



  • @anonymous234 said:

    With side effects, I could just tell a function to do something arbitrarily complex for me, now instead I have to know exactly what resources the function needs to do it and obtain/create them myself.

    Right, you spend an extra $5 here to avoid spending an unexpected $20 over there.


  • I survived the hour long Uno hand

    I dunno. Any number of libraries or APIs that don't need to preserve state between calls sound like they'd be good candidates for a functional approach.



  • So what if...

    the language acknowledges that implicit parameters are a thing, but keeps them separate from normal parameters?

    For example, it could make you declare them, something like

        public Program getCurrentProgram(TVGuide guide, int channel)
        implicit_parameters(Date when = new Date())
        {
          Schedule schedule = guide.getSchedule(channel);
          Program program = schedule.programAt(when);
          return program;
        }
    

    So now the function works as it did externally, but from the full signature it's very clear that it uses a Date() (so it solves the problem of being able to see when a function calls a database), and the language could provide a way to call them with different values (so it solves the problem of testing).

    ...and I just realized I reinvented optional parameters.



  • @anonymous234 said:

    ...and I just realized I reinvented optional parameters.

    I was about to say.



  • Just write two functions:

        public Program getProgramAt(TVGuide guide, int channel, Date when) {
          Schedule schedule = guide.getSchedule(channel);
          Program program = schedule.programAt(when);
          return program;
        }
        public Program getCurrentProgram(TVGuide guide, int channel) {
            return getProgramAt(guide, channel, new Date());
        }
    

    I don't mind a function like getCurrentProgram in this case 'cause we've still separated the business logic from the side-effect. You could still reuse or write a unit test for a function like getProgramAt.

    It also addresses these concerns:

    @anonymous234 said:

    Now I have to call new Date() myself when previously the function did it for me.

    With side effects, I could just tell a function to do something arbitrarily complex for me, now instead I have to know exactly what resources the function needs to do it and obtain/create them myself.

    Separating side effects is just another way of doing separation of concerns. Passing them into dependent code is dependency injection. It's not really that new or controversial of a concept.


  • Discourse touched me in a no-no place

    @asdf said:

    I think functional programming languages are rarely the right tool for a job, because they disallow side-effects altogether.

    Haskell and Clojure both allow side-effects, but keep them isolated. Which programming languages are you talking about?


  • area_deu

    Even Ruby kind of does that, with its ! naming convention.


  • Discourse touched me in a no-no place

    @julmu said:

    > public Program getCurrentProgram(TVGuide guide, int channel) {

    This function has a hidden input of the current time (new Date()).

    I wouldn't consider the input to be hidden if it's in the name of the function.

    It's not passed into the function as an explicit parameter, that's what he means by 'hidden,' and it's not part of the name of the function.


  • Winner of the 2016 Presidential Election

    @antiquarian said:

    Haskell and Clojure both allow side-effects, but keep them isolated.

    Are you talking about monads now?


  • Discourse touched me in a no-no place

    @asdf said:

    Are you talking about monads now?

    Yes, specifically the IO and State monads.



  • @cartman82 said:

    dogma-filled academic circlejerk

    9/10ths of what makes up functional programming in the wild, is exactly this. So; accurate explanation?



  • The fact that this guy missed immutable objects is a bit odd. They pretty much eliminate side effects too, which is what he's looking at.

    I'm doing some TDD practice in my spare time where everything is immutable and pure, and rather enjoying it.



  • If everything is immutable, then you have to recurse, no? From that perspective things become mutable again and you will have to worry about side effects again.



  • If trees are butterflies, then you have to space, no?

    No. Whatever you're talking about makes no sense at all.

    Unless you mean even counting variables for loops can't be mutable, but that's completely stupid.



  • I thought tail recursion was a thing? How would you make a game "where everything is immutable and pure"?

    @Magus said:

    Unless you mean even counting variables for loops can't be mutable, but that's completely stupid.
    I don't know what you mean by "everything"



  • Do you really not get it? The only problem this guy had was with methods changing the state of some object. Functional programming doesn't do well with that. Changing local variables doesn't make something non-functional. An argument could easily be made that you should try to avoid even local state, but that's rather restrictive and doesn't achieve much except making really crazy people happy.


  • Winner of the 2016 Presidential Election

    @antiquarian said:

    Yes, specifically the IO and State monads.

    Ok, what I said was technically wrong. Replace "side-effects" with "hiding side-effects" in the post you replied to.

    BTW: An interesting concept for encapsulating state changes:



  • @Magus said:

    Do you really not get it?

    I understand the article. I do not understand you.


  • Discourse touched me in a no-no place

    @asdf said:

    Ok, what I said was technically wrong. Replace "side-effects" with "hiding side-effects" in the post you replied to.

    :pendant: fail


  • Winner of the 2016 Presidential Election

    @antiquarian said:

    :pendant: fail

    E_NOT_ENOUGH_DICKWEEDRY


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.