2

I have an intuition, that I'd like to read what others have talked about. To me, it seems fairly intuitive that when you have a function which is called multiple times with the same arguments, it would be better to create an abstraction which doesn't require arguments, to avoid duplication. So for example, if I have:

getErrorMessage(username, 'foo', 'bar') written 3 times in the code, I'd probably want an abstraction such as the following (provided that each of the 3 places has the same reason for changing).

function getFooBarErrorMessage(username) {
   return getErrorMessage(username, 'foo', 'bar')
}

This, to me, seems clearly better, because I'm reducing the amount of mental entities involved in each function call, making the different instances of the function call consistent among themselves, and reducing the possibility of errors.

The possibility of errors seem to grow exponentially with the number of parameters, but I'd actually still think it's worth doing it even if there was a single parameter, but the call with that parameter was repeated more than once.

What I'm wondering is if there are good theoretical treatments of this question by scholars, (or even a good popular article will do as well), since I couldn't find anything.

3
  • On the other hand having too many functions for the same task can make your API more difficult to read, and make the code less recognizable. Commented Oct 13, 2022 at 11:19
  • This, to me, seems clearly better, because I'm reducing the number of mental entities involved when you read code and you have to repeat the very same code a hundred times, you really appreciate the abstractions you suggest. I definitely implement the abstractions and my code seems way more readable. On the other hand, the fewer arguments have a function, the better. It has been always that way, it's also in this particular case.
    – Laiv
    Commented Oct 13, 2022 at 11:39
  • I believe the thing you are referring to is called a "Partial function" in Python and a "partially applied function" in Haskell. I imagine with those search terms you might be better able to find theoretical treatments by scholars.
    – John Wu
    Commented Oct 13, 2022 at 21:59

2 Answers 2

2

What I'm wondering is if there are good theoretical treatments of this question by scholars, (or even a good popular article will do as well), since I couldn't find anything.

Not really. However, you will read often that the fewer arguments the better. Zero-argument functions are ideal. This is especially true when arguments are unnecessary because the function already has access to them. Or when defaults are allowed. The less information you force "others" to know, the better (IMO).

This, to me, seems better because I'm reducing the number of mental entities involved in each function call,

This reasoning is perfectly legit. Better or not, I don't dare to say. It's practical and I have found that it makes my code easier to read.

Think in loggers. There should be a reason why loggers provide log.warn(message) and log.error(message) instead of (and only) logger.log(level, message). They hide details you don't need to know. Details that they can provide by themselves.

This is, probably, due to most of the implementations will never use logger.log(level, message). Most won't make the level to be dynamic. So, why would they mess you with it?

4

It doesn't really make a difference in the number of mental entities, as the parts of the function name in composite names such as getFooBarErrorMessage also constitute mental entities. You just moved them from the parameter list where the reader could quickly see that this is just the plain old getErrorMessage with 'foo' and 'bar' arguments to a new function that the reader would have to look up to confirm that it doesn't do anything else but pass these two arguments to the generic function.

For 3 repeated cases, I would probably not want to refactor. If there are many more, you should certainly question your choice of interfaces. It may be reasonable to introduce such a shorthand (but please give it a meaningful name) but it may as well make sense to refactor the surrounding code as well, because the error message is probably always caused by very similar operations, which would be the preferable target of refactoring.

1
  • Yeah, I understand your points. To be fair, the example was pretty contrived. If a certain message has this same structure, it would probably have a more meaningful name. Although, whether or not "mental entity" is the correct term, I do think it's easier to think of when reading, since it's a single reference to a single entity, as opposed to a reference to a function + 2 arguments (which ideally would also be constants) so we're using a combination of 3 entities, instead of a single entity. Commented Oct 13, 2022 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.