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]