You are currently viewing Dependency injection with function types has some shortcomings compared to interfaces

Dependency injection with function types has some shortcomings compared to interfaces

One thing you sometimes find is that a code base may have a Foo interface that has several methods. When you’re writing a new function, you may only need one of those methods to operate:

interface Foo { fun doSomethingWithInt(x: Int): Int? fun doSomethingWithString(x: String): String? fun doSomethingWithBar(x: Bar): Bar? } fun coolNewStringFeature(foo: Foo): String? { // stuff return foo.doSomethingWithString("string") } 

Now, if you want to test your coolNewStringFeature you have to mock/stub the whole interface. Either by hand, or with some mock library like mockk. On the other hand, if you just wrote your function as:

fun coolNewStringFeature(doSomethingWithString: (String) -> String?): String? { // stuff return doSomethingWithString("string") } 

Now you just have to write a trivial closure to test the function! And it’s easy to quickly test a bunch of different inputs, instead of fiddling with your mocks or whatever.

But there are problems.

Problem #1: Function types can’t have arg labels.

fun withRange(operation: (min: Int, max: Int) -> Boolean) { operation(min = 0, max = 2) // compile error operation(0, 2) // which one means what? } interface MinMaxinator { fun operation(min: Int, max: Int) = //... } fun withRange(operator: MinMaxinator) { operator.operation(min = 0, max = 2) // okay! } 

Problem #2: Functions with default args can’t be used as function types without those args.

fun importantWork(x: Int, y: Int, z: Int = 10) = //... fun doWith(work: (Int, Int) -> Unit) = //... doWith(::importantWork) // compile error 

Just putting this out there. No real question. Just generally complaining about stuff 🙂

I like the idea of passing functions around instead of objects, but I keep running into papercuts.

submitted by /u/ragnese
[link] [comments]