You can't really do this and avoid the repetition, because when you provide an argument in when (something)
the something is an expression that produces a value, which is fixed before the matching starts. And then your branch expressions are compared to that fixed value, trying to find an equals
match (or a few other special cases, like is
or in
)
The closest you can get is what sirjoga is going for, where you don't provide an argument to when
, so the branch conditions are just simple boolean expressions. So instead of each condition being a value trying to match that something value, you make a function call that produces a true or false value, and the when
block uses the first one that matches true.
If you really need to avoid the repetition while keeping it looking like a standard when
matcher, you could do something like this:
fun <T, R> when2( predicate: (T) -> Boolean, matchers: Map<T, () -> R>, default: () -> R) : R{ val match = matchers.entries.firstOrNull { predicate(it.key) }?.value ?: default return match.invoke()}fun main() { val thing = "this is a sentence" when2({ thing.startsWith(it) }, mapOf("this" to { println("Starts with this") },"that" to { println("Starts with that") } ), default = { println("uh oh") } )}
But then you're creating a Map
each time it's called, instead of getting compiled neatly into some basic conditional code. You could create a stateful object (so you pass this all into the function call, but it stores it and returns an object that lets you do checks):
fun <T, R> whenMaker( matchers: Map<T, () -> R>, default: () -> R) : ((T) -> Boolean) -> R{ return { predicate -> val match = matchers.entries.firstOrNull { predicate(it.key) }?.value ?: default match.invoke() }}fun main() { val match = whenMaker( mapOf("this" to { println("Starts with this") },"that" to { println("Starts with that") } ), default = { println("uh oh") } ) match { "this is a sentence".startsWith(it) } match { "that is a sentence".startsWith(it) } match { "them is a sentence".startsWith(it) }}
But now you're separating the definition of your when
structure from where it's actually used - especially as ideally, you wouldn't be creating that match
object inside your function since that could happen repeatedly. But, depending on what you're doing and how much it matters, something like this could be useful! E.g. a convenience class that defines the match
object in a top-level variable, directly above the function that makes use of it might not be so bad.