10

Let's say, for example, that I have a function makeFoo that makes another function foo:

function makeFoo(string) {
    return () => string
}

const foo = makeFoo('bar');

I know that makeFoo is a higher-order function because it returns a function, but is makeFoo the best name? Would something like createFoo or fooFactory or provideFoo be better? Is there any sort of standard at all?

5
  • 2
    It depends on the language. Each has their own idioms and cultures which have different expectations about names.
    – Telastyn
    Commented Jul 16, 2020 at 3:25
  • Can you give some examples, for let's say Java or JavaScript
    – Splox
    Commented Jul 16, 2020 at 5:53
  • 3
    What would be a good name for the makeFoo function in an arbitrary situation depends entirely on what the purpose of the function is in that specific situation; there is no generic, correct answer to your question.
    – Jesper
    Commented Jul 16, 2020 at 7:29
  • 1
    As well as endorsing the other comments, I'd say that "make" is not a great word to describe what is happening here. The function returns or gives a function, but it's not apparent that it makes a function here in any sense of creation or assembly from parts, unless you yourself use "make" consistently as a synonym for return or give (as in "2 plus.2 makes 4", "10 divided by 2 makes 5", etc.). But in the latter case, it should be obvious that function names should rarely if ever include the word "return" or "give", because returning is inherent to the nature of all functions.
    – Steve
    Commented Jul 16, 2020 at 12:03
  • fooFor(.....) Commented May 26, 2022 at 20:18

5 Answers 5

11

Pattern-like names are very much an OOP convention. In FP, higher-order functions aren't a pattern, they're just syntax. You typically use names that go with the domain.

Functions that return a function aren't usually thought of as creating a function, but as supplying parts of the arguments to a function at different times. In languages that support a curried function argument syntax, you almost always use that instead of the way you wrote it. This is usually to meet the signature requirements of some callback function.

For example:

const logEvent = (string) => () => console.log(string);

document.getElementById("myButton").onclick = logEvent("myButton clicked!");
document.getElementById("another").onclick = logEvent("another clicked!");

  

Here, onclick requires a function, but I don't want to repeat the clutter of anonymous functions all over the place, so I create a curried function. The logEvent name describes the function that eventually happens when the onclick event occurs. Note if I had named this something like createStringClickHandler, it would be a lot more difficult to determine at the calling point what it's actually doing.

2
  • 3
    What about createLogEvent? To me this makes more sense because it accurately defines what the function is actually doing, especially when I might be doing something like const fooLogEvent = () => console.log('foo'); elsewhere in the code.
    – Splox
    Commented Jul 16, 2020 at 19:49
  • @Splox document.getElementById("another").onclick = logEvent("another clicked!"); translates for me to: the onclick behavior ist to log an event ("another clicked!") which feels natural to me. From your example given I would name the second function logFooEvent. Commented May 27, 2022 at 8:21
5

As you ask specifically for what this is called in Java I'd say for your specific example its a StringSupplierSupplier or Supplier<Supplier<String>> https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html but I wouldn't necessarily call it that.

In general a function that returns a function is the same as a function with an extra argument (possibly with lazier evaluation) so often there will not be a special name for this. e.g. we can implement add as:

int add (int a, int b) { return a + b;}
add(2,3); //5

but we can also implement it as:

int add (int a) { return b => a + b;}
add(2)(3); //5
3
  • 2
    in fact i'd probably go as far to say that in a satically typed language with a decent type system you shouldnt repeat type information in your identifiers
    – jk.
    Commented Jul 16, 2020 at 8:40
  • I'm not sure the first paragraph is relevant: they are looking for the name of something that returns such a supplier, not the supplier itself. Commented Jul 16, 2020 at 12:53
  • @VisualMelon yep youd want an extra level of Supplier in there for that... which would probably not be a good idea
    – jk.
    Commented Jul 16, 2020 at 15:21
3

Create or factory or make are all wrong because from the perspective of the caller it is about the process of obtaining the function, not about the creation of it (this is a hidden detail, you do not care if it was created on the fly or waiting for you to collect, you just want to have it now). So it should be something like GetDoWhatever().

The variable you assign the result to would be doWhatever().

2
  • 1
    My concern for this is that in some languages like Java, this could be confused with a property getter.
    – Splox
    Commented Jul 16, 2020 at 6:43
  • 3
    @Splox If it clashes with a convention you can use a different word (e.g. obtain, retrieve, gimme). I think it is important to preserve the meaning of getting the function and not include details about the way the function was constructed. Commented Jul 16, 2020 at 8:26
0

My teams uses acquire, but there is NO widespread convention

acquire

  • buy or obtain (an asset or object) for oneself.
  • learn or develop (a skill, habit, or quality).
const acquireLogEvent = (string) => () => console.log(string);

document.getElementById("myButton").onclick = acquireLogEvent("myButton clicked!");
document.getElementById("another").onclick = acquireLogEvent("another clicked!");
const acquireSortBy = (key) => (a, b) => a[key] - b[key]
const sortByBasePay = acquireSortBy('basePay')

managers.sort(sortByBasePay)
workers.sort(sortByBasePay)
workers.sort(acquireSortBy('yearsWorked'))

My first instinct was to use get as an obvious description of the action. But as mentioned by @Splox get was NOT unique to returning functions. My second attempt was getFunction, but this added clutter and I was inconsistent with placement (getSortByFunction / getFunctionSortBy). I looked up synonyms for get and acquire was the best fit. (This is inline with @Martin Matt comment: "it is important to preserve the meaning of getting the function")

In an untyped language conventions like this are essential for understanding code and avoiding mistakes. I hope more please think like @Spolx.

0

In TXR Lisp, I called the function retf. It produces a function which just returns the specified value. Higher order code reads well with that name.

I also use the f suffix in some place to indicate a functional result; for instance iff is like if, but functional.

Here is an example with iff and retf:

1> (mapcar [iff oddp (retf 1) (retf 0)] 0..10)
(0 1 0 1 0 1 0 1 0 1)

Map the list of integers 0 to 9 through a function which returns 1 for odd integers, otherwise 0.

iff is a function which has functional arguments. oddp is a built-in function and (ret 1) and (ret 0) return functions. iff passes its arguments to oddp. If that function yields true, then it calls (retf 1), otherwise it calls (retf 2).

So it's like the (if cond then else) operator except that rather than evaluating expressions, it calls functions [iff cond-function then-function else-function].

In this language, there is a ret macro. Wnen you evaluate (retf expr), expr is eagerly evaluated to an argument value, and retf is called, return a function which returns that value. By contrast, when (ret expr) is evaluated, it returns a function which, when called, will evaluate expr at that time (and every time it is called) and return the value.

1> (let ((i 0)) (ret (inc i)))
#<interpreted fun: lambda #:arg-rest-0015>
2> [*1]
1
3> [*1]
2
4> [*1]
3
5> (let ((i 0)) (retf (inc i)))
#<intrinsic fun: 0 param + variadic>
6> [*5]
1
7> [*5]
1
8> [*5]
1

Here, the function produced by ret is capable of incrementing i each time it is called and returning the incremented value, whereas the retf function has just captured the value 1 and returns that.

If you don't have these kinds of evaluation situations to worry about, using the name ret for the function-returning function might make sense.

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