javascriptperformancedefault-arguments

Performance implications of using complex objects as default parameter


EDIT: looks like I was incorrect about Python's issue - it's with mutability, not performance

Thank you for helping me correct my understanding of the problem. I'm leaving this up in case someone has a similar confusion. If you are looking for an overview of mutability in JS default parameters, this question may be useful.

Original Question:

I want to use a very complicated object as a default parameter. For example, in prisma ORM, you can wrap multiple db calls in a transaction:

this.prisma.$transaction(async (tx) => {
  await tx.table1.create()
  await tx.table2.create()
}

These inner db calls can be complicated, so I may want helper functions for them. However, the helper functions can be called from many places and may or may not be used inside a transaction. To solve this, I optionally pass the transaction, and use it if it exists:

// My function with a complex default param
async createModelIfNotExists(name, color, prisma = this.prisma) {
  return await prisma.upsert({...})
}

...

// Call from within transaction, and use transaction's prisma client:
this.prisma.$transaction(async (tx) => {
  this.createModelIfNotExists("new model 1", "blue", tx)
  ...
})

// Call on its own, and it will use the prisma object attached to "this"
this.createModelIfNotExists("new model 2", "green")

Note that tx is a very large & complex object. It manages the db connection and keeps track of all my models.

My question is - is there a performance overhead to doing this? If I was writing Python, there would be, because Python tries to be smart & initializes the default parameter even if you don't use the function. If I wrote it like Python, the function signature would look like this:

// The default param is now instantiated in the function
async createModelIfNotExists(name, color, prisma = null) {
  prisma = prisma ?? this.prisma
  return await prisma.upsert({...})
}

I am concerned about the potential overhead of instantiating this object even when it's not used.

I tried Googling this, but have only seen results for more basic JS objects that the programmer writes themselves.

Alternatively, if you have suggestions on how to test the performance of this, I could do that instead.


Solution

  • Seems the default parameter is initialized when it's needed, so no any performance hit. Though a default parameter is initiated every time with a new object.

    That's in general, but in your case you are using already existing object, so nothing actually created/initialized, the argument is just initialized with an existing object's reference, so no performance hit again.

    class Test{
      param = false;
      constructor(){
        console.log('Test is being constructed');
      }
    }
    
    function func(test = new Test){
       console.log(test.param);
       test.param = true;
       
    }
    
    func({});
    func();
    func();