You can read all about overloading the invoke operator on a companion object in this blogpost by Ataul Munim:

The context there is around validation before the object creation. The point of this post is to highlight another interesting scenario where I found this useful.

Coroutines testing

We've been increasingly using coroutines at Blinkist and we wanted to introduce in our codebase a JUnit rule like this one:

But I didn't want to only support TestCoroutineDispatcher , I wanted to give a way for clients to also use the Unconfined dispatcher for simple scenarios. In fact, I wanted Unconfined to be the default, and I still wanted to expose the dispatcher so clients would be able to use it in case they chose to work with the TestCoroutineDispatcher . I basically agree with Zach Klippenstein here:

I also want to make sure I'm exposing the actual type of the dispatcher I'm using, so when clients are using a TestCoroutineDispatcher , they can do something like this, for instance:

rule.dispatcher.advanceTimeBy(500)

That's why generics is important here and I don't want to expose the dispatcher as a simple CoroutineDispatcher , which ultimately would lead to ugly casts in the clients.

So this was my first attempt:

But it won't compile:

Type mismatch.

Required: T

Found: CoroutineDispatcher

There are some discussions about this, and currently there's no ETA for this feature. It took me a while to accept this wasn't possible, but I was lucky to have fresh in my memory something that could help me there. I had recently watched this great talk by Danny Preussler where he mentions overloading the invoke operator on companion objects:

This is how our rule looks like with that trick:

Now anyone wanting to write a simple coroutine test can just go with a CoroutineRule() , and anyone interested in the power of the TestCoroutineDispatcher can explicitly pass it in the constructor ✨

I agree with Ataul Munim that this still causes some astonishment, and in the end we actually decided to add a comment there explaining what's going on: