4

I often use function closures for storing data (e.g. database URL), which doesn't change between function calls. Is this an (anti-)pattern? Does it have a name?


While developing apps, which recieve data, process and send data (using a variety of protocolls), I stumpled upon this recurring problem:

A functions needs 4 or more paramters to performe it's task, while only one (or two) of these parameters change between calls. E.g.:(1) A function sending data, which needs the ip-address and the port of the destination, something for authorization and the data to send. E.g.:(2) A function processing raw data into the format of a database, which needs information about the raw data, the database and the raw data itself.

My original approach was to store this information where the function is called and just pass it everytime I call the function. But I find this quite hard to read, so I searched for a solution to store the constant parameters elsewhere. One thing I considered, was packing these into objects, but JS does not support private and constant attributes + this functions are often used as callback functions.

Of course I could use method_name.bind(the_object); , but using closures seemed to solve the problem as well, wouldn't require usage of ````this``` and seemed more 'functional' than the other approach and therefore more fit for JS.

So my implementation of such a function usually looks like this:

function create_processData(schema, connectionInfosForAnotherDB, (...)){

    const someImportantInfo = getTheInfoFromAnotherDB(connectionInfosForAnotherDB);
    const interpretationOfThatInfo = interpretThatInfo(someImportantInfo);
    let processedMessageCounter = 0;

    function processData(data){
        //do the processing using the schema and the interpretationOfThatInfo
        //also use the processedMessageCounter
        processedMessageCounter++;
        return processedData;
    }
    return processData;

}
module.exports = create_processData;

I have a function (create_processData) which setUps everything the actual function(processData) needs to work and save it's in it's closure, so that the actual function can access it. Then I return a reference to the actual function.

Code which uses this function would look like this:

const create_processData = require("./the_path/processData");
const processData = create_processData(...);

//use the processData function in a callback or something similar 

Unfortunatly, this doesn't provide the clearity of code I wanted to achieve (while enabling a whole lot of encapsulation and keeping data only where it is needed - which I do like). In addition to that, a the code feels hard to understand, but this may just be a result of me beeing used to OOP and beeing unfamilier to functional programming (I don't have a exhaustive experience or knowledge of both of them).

I tried to do some research about this, but I didn't find anything usefull. Probably, this is due to a lack of vocabulary for this type of problem, pattern etc.

So: is this a known (anti-)pattern or problem? Does it have a name? (Or is there just an obvious flaw in my thinking, which just isn't obvious to me?)

2
  • 3
    Since you've said that you are more used to OOP, then think of it like this: this is no different than using a factory to create an object (the factory preconfigures it in some way, and returns a ready-to-(re)use instance). You can think of a function as of a single-method object (and in JS, functions are objects anyway), that has been preconfigured by the create_ function. After all "closures are poor man's objects, and vice versa" (see this). As for clarity, you could improve it by finding a better name than 'processData'. Commented Sep 30, 2020 at 15:48
  • news.ycombinator.com/item?id=926140
    – jk.
    Commented Oct 5, 2020 at 7:49

3 Answers 3

13

This is just using closures.

When you're from an OO background building and using a closure ends up feeling like using constructors/factories and methods, respectively. The big difference is you just get the one "method". Oh and you don’t get any of that silly new business anymore.

Of course functions are first class citizens here and can be shoved into variables that give them new names. So there are other differences as well. But the state of the "enclosing scope" of a closure can end up feeling very much like the state of an object.

Look up currying and binding if you want to get deep into this.

I don't see an anti pattern here. Just use good names.

1
  • 1
    "currying" and "binding" were the words I searched for. Thanks a lot! Commented Oct 1, 2020 at 8:08
3

As @candied_orange mentioned, what you're doing there is very similar to currying. Its worth learning about.

Javascript arrow functions were designed to allow for easy currying. An example of a fully curried function:

// Definition
let dbRequest = connectionInfo => options => query => {
  // ...
}
// Usage:
myConnectionInfo = ...
myOptions = ...
let doQuery = dbRequest(myConnectionInfo)(myOptions)
doQuery(myQuery)

However, you can do "partial function application" without currying by moving the job of function splitting to the consumer of your API.

// Definition
let dbRequest = (connectionInfo, options, query) => {
  // ...
}
// Usage:
myConnectionInfo = ...
myOptions = ...
doQuery = (query) => dbRequest(myConnectionInfo, myOptions, query)
doQuery(myQuery)

You may find these shorthand syntax examples helpful in general, but because you're doing an expensive operation with the first parameter that shouldn't be repeated, some tailoring would be needed.

What your code actually reminds me of is a factory function (effectively an alternative way to get class-like behavior, which some people prefer).

function createDbConnection(connectionInfo, options) {
  // Expensive (or non-expensive) setup
  return {
    query() { ... },
    // Any other functions you might want to provide
  }
}

What you currently have works just fine also, I would be able to understand that code just fine if I found it in a codebase. But hopefully these other possibilities can help expand your toolset.

1
  • Your Snippets are defenitly something I will add to my JS-Toolset. Thanks a lot! Commented Oct 2, 2020 at 10:54
2

Functions are objects. The have but one entry point instead of multiple methods but this limitation does not change their basic nature. Closures are configurable objects. When closures capture references to mutable data, or if they are allowed to directly write to their captured values (using upvalues, like in JS or Lua), they can even be stateful objects.

It is very convenient to not have to write a class for creating an object but please take extreme care for readability and immediate understandability of what you're doing / the API that you are providing when writing stateful closures 😉

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.