News for hackers. Stuff that matters.
Re:When Does Point-Free Notation Make Code More Readable? by Jtsummers on Friday September 29, 2017 @02:04PM (#15367578)
Why would you want to do this? For exactly the same reason we don't want to see so-called "magic numbers" throughout our code. An equivalent question might be: Why should I use MAX_INT16 instead of 32767 everywhere? They encode precisely the same thing, but one is just a number and the other offers a meaningful name as well as one location where it's defined, reducing the risk of error. Or maybe you really want MAX_INTEGER which will be determined by your hardware platform, again you only have one place to redefine the value and not throughout your codebase. Maybe 32767 was selected in some places because it was the system's MAX_INTEGER, and in others it has some different meaning or reason for being used that shouldn't be altered by changing MAX_INTEGER.

Back to atLeastTwo. It's a trivial example, but consider if you actually did have Math.max(2, e) throughout your code base. What is the meaning of this expression? Gives you either 2 or e whichever is greater. Great, we understand what it is. But now, why? What is magic about 2. Giving it a name can convey the why (though atLeastTwo does not). Giving it a name also makes it less error-prone. Suppose you fat-fingered 22 into a couple spots, how do you (quickly and easily) identify that error? If it's just Math.max(22, <expression>) you can't even know whether it's wrong, just that it has a 22 in it instead of a 2.

Sufficient testing would (hopefully) reveal that you used 22 instead of 2, but it may lead to subtle bugs that are hard to identify. We have this issue in a codebase at work where we do a lot of bit twiddling. Instead of setXFlag(&data_word, val) we have something like setBits(7,1,&data_word,val). That 7,1 determines which bit to start at (7) and how many (1) to put val into. Great, it works. But when the data format got changed we had to change every single reference to 7,1 to 6,1. Unfortunately it was really, really fucking hard to find all those references and correctly discern which ones needed to be changed and which ones didn't.

Re:When Does Point-Free Notation Make Code More Readable? by tzs on Friday September 29, 2017 @03:16PM (#15368272)
I agree that a literal 2 is probably bad to use in "Math.max(2, e)", but it is also probably as bad in "partial(Math.max, 2)", and even worse is the "Two" embedded in the function name in "function atLeastTwo(someNumber) {...}".

I decided to let that ride rather than change it to something like MIN_SAFE_VALUE like it should be in real code.

So supposed that is fixed, and we have MIN_SAFE_VALUE defined somewhere, so that we don't have to worry about typos (much...if we have a MIN_SAVE_VALUE too that could be trouble).

Also suppose that MIN_SAFE_VALUE is used instead of 2 in "partial(Math.max, ...)". Alternatively, if that is the only place that actually uses MIN_SAFE_VALUE, with everyone else using it via the partial function, then I suppose it would be OK to use the 2 literally there, and name the result of partial with a name that says it it ensures the minimum safe value.

Same for the "function atLeastTwo" approach. Give it a good name, and get rid of the magic number in the definition, unless that is the only place that uses MIN_SAFE_VALUE directly and then maybe it is OK for that to be where the literal 2 appears and not have a MIN_SAFE_VALUE constant defined. (I'd still go for a defined constant, because it and any other such magic numbers can be defined in one place making it easier for people who need to tune things later).

Now I can see why the "partial" approach and the regular function approach might win over inline "Math.max(MIN_SAFE_VALUE, ...)", because they both make it easier to change how the safety constraint is enforced.

For example let's say this code is part of the control system for a power plant. The engineers revise the rules to allow going 10% under the normal minimum safe value when the plant is operating more than 20% below peak capacity.

With the regular function approach we only have to change that one function so that it checks the operating level and adjusts the threshold it checks against accordingly. With the partial approach we could probably also do something like that (although maybe we'd need a helper function since we would no longer be applying partial to an already existing function.

With the "Math.max(MIN_SAFE_VALUE, ...)" everywhere approach we'd have to change all those places. (Except if we were in C or C++, and MIN_SAFE_VALUE was a simple #define. Then maybe we could change that from "#define MIN_SAFE_VALUE 2" to "#define MIN_SAFE_VALUE current_safe_value()" and write a current_safe_value() function. That still limits is to only handling safe value rules that involve a >= comparison of the value with a threshold, so is still not as flexible as the normal function approach.

But note that this advantage comes from pushing the algorithm of the safety check down to underlying functions, instead of exposing it at the point of use. Using Math.max at the place where you are actually checking the value and using the corrected value exposes at that point that the algorithm is to compare to something and pick the larger of the two.

For me the article just didn't explain why pushing the algorithms lower in point-free style is better than doing that in normal function style, and didn't seem to have any other compelling thing point-free does. This is probably a topic that needs more than the 148 words in the article's "Why Does It Matter?" section.

Some of the comments here using Haskell look more interesting, but I've only looked a little at Haskell. They all quickly hit my limit--the before and after Haskell examples look like something compelling is happening but I just am not yet able to see what that is.