top | item 15507081

Functional calisthenics

69 points| pedromsantos | 8 years ago |codurance.com | reply

36 comments

order
[+] maxxxxx|8 years ago|reply
Isn't this going a little overboard?

I remember when OOP came up, some people made functions illegal. So instead of

s = sinx(x)

the OOP way was

m = new Math() s = m.sin(x)

And instead of switch statements you had to derive a new class for each case call a virtual function. Very "OOP" but it led to the OOP equivalent of spaghetti code.

Are the functional guys also starting to leave the real world for the sake of being "pure"?

[+] MiyamotoAkira|8 years ago|reply
Author here. A few have mentioned already, but this is to practice, to force you to understand what FP brings to the table, and lead you in path of discovery. When it comes to production code, you apply what you have learned, and make the decisions that you think more convenient. As an example, if you want certain performance gains on F# you do go to mutable state (Phil Trelford did a talk about it). Doesn't matter how pretty/OO/pure is the code if your application doesn't do what is supposed to ;-)
[+] munificent|8 years ago|reply
The article states:

    These rules are constraints on how to create your code
    and are only intended to be applied when doing katas or
    exercises.
These rules are an exercise to kick you out of an OOP mindset, not best practices for writing real code.

By that same token, I think it is a good rule when practicing OOP to not allow bare functions. It helps train yourself to think "Is there a logical class that this method belongs to?" In real code, of course, the answer is often "no". But when first learning OOP, it's good to teach yourself to ask that question in the first place.

Your code isn't a good example of "the OOP way", though. A fluent OOP solution would be:

    s = x.sin()
Another good rule when practicing OOP would be "No classes without state." That helps you avoid the habit of writing pointless "namespace" classes like the "Math" class you define here. Of course, again, sometimes it is useful to wrap a bunch of related behavior in a stateless class, but that should be the exception, not the default.
[+] Veen|8 years ago|reply
I think it's more of an exercise than a stringent philosophy. Looking at these rules, they're designed to be helpful for cultivating functional habits and patterns of thought if you're not used to thinking and coding that way.

I wouldn't expect anyone to follow them religiously in production code.

[+] emsy|8 years ago|reply
>And instead of switch statements you had to derive a new class for each case call a virtual function. Very "OOP" but it led to the OOP equivalent of spaghetti code.

I disagree. Switch statements are fine to react to incoming data, but terrible for everything else. If you add a value to an enum you have to change every place where the enum is used in a switch. And the code inside the switch is not reusable (Unless you make it a method, at which point you're close to the "OOP" way anyway). I agree that religiously avoiding switches lead to spaghetti code, but mindlessly using them does so too.

[+] epidemian|8 years ago|reply
Nitpick, but why

  m = new Math() s = m.sin(x)
would be "the OOP way" instead of

  x.sin  
?

Besides this nitpick, i concur with Veen. The post seems to be about exercises/challenges, not FP best practices.

[+] nextos|8 years ago|reply
sinx(x) can be still object-oriented. Actually, really neat object oriented systems which implement multiple dispatch, like CLOS, tend to use this notation.
[+] crimsonalucard|8 years ago|reply
No. Almost every functional language forces you to follow these "calisthenics." These look more like guidelines to follow if you want to execute the functional style in an imperative language.
[+] CJefferson|8 years ago|reply
I don't understand "no explicit recursion". How do you do any kind of binary tree search without recursion?
[+] abecedarius|8 years ago|reply
This is in contrast with structural recursion. When you define a binary tree datatype you should get for free a generic fold operation on these trees, analogous to the map and reduce functions on lists. I don't know if Clojure gives you that.
[+] MiyamotoAkira|8 years ago|reply
The people that talked about the rules at Codurance was none of the people that defined the original rules. We had to "reverse engineer" the thinking, find reasons and then discard, change or let as they were (one of the objectives of the write up was to put down those reasons). Explicit recursion did take a while. The reasoning we came with is to learn to use map/reduce functions (do take into account that our group has an ecletic knowdledge of FP and hybrid languages: Clojure, Haskel, Elixir, Scala, F#, ...). Can that binary search tree be converted into a linear search if you rearrange the tree into a list? Yes. Now you can use map /reduce. Is it performant? Most probably not. Are there other ways? Time to discover. Interestingly, most of the katas/exercises on which we are practicing these rules are not heavily algorithmic in nature. Maybe we do need to add some to understand better and modify the "rules" with the new knowledge.
[+] danidiaz|8 years ago|reply
Here is an answer in the CS Theory Stack Exchange that explains how: https://cstheory.stackexchange.com/a/18399/13730 (I'm not endorsing it as a practical way of doing it, mind you.)

The idea is that the only explicit recursion is contained in generic combinators "fold_result" and "unfold_result" that are "boring" in the sense that they can be derived mechanically from the "resultF" data type and do not actually know about the binary search; they just do recursion.

In practice, folds and unfolds tend to be more useful for other things.

[+] crimsonalucard|8 years ago|reply
I wouldn't even call these things calisthenics. These are requirements for the programming style to be called "functional."

Really if you aren't following <Edit> Most <Edit> of these rules you are not doing functional programming.

The best way to learn about functional is not to follow these rules but to use a functional language that basically enforces these rules. Javascript is not a good language to learn about functional programming.

[+] jw-|8 years ago|reply
I'm not really sure why you need the requirement of infinite sequences to do functional programming, or the restriction of no intermediate variables. Let bindings seem like a nice thing to have.
[+] MiyamotoAkira|8 years ago|reply
You are right. If you don't follow most of those rules, you are not doing pure FP. My interest on them was because I was writing production code that felt procedural. The rules are there so you can practice with purpose. Once you go into production code, you can discard them, but with knowledge that it will not be because your OOP skills take over, but conscious decisions.
[+] gaius|8 years ago|reply
I came here expecting an article on CrossFit!