Skip to content

Instantly share code, notes, and snippets.

@Meodinger
Last active December 13, 2021 04:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Meodinger/e624bc0e0fbc093789cc6e245da43535 to your computer and use it in GitHub Desktop.
Save Meodinger/e624bc0e0fbc093789cc6e245da43535 to your computer and use it in GitHub Desktop.
Kotlin if-implicit-boolean-conversion
/**
* Support implicit conversion form Any? to boolean
* Use JavaScript standard
* Example: (_if_({ null }) { 0 } _else_ { 1 })() -> 1
*/
open class _if_<T>(private val condition: () -> Any?, private val ifBlock: () -> T) {
companion object {
fun Any?.logic(): Boolean {
return when (this) {
is Unit -> false
is Boolean -> this
is Number -> this != 0 && !this.toDouble().isNaN()
is String -> this.isNotEmpty()
else -> this != null
}
}
private val DEFAULT_BLOCK: () -> Nothing = { throw NotImplementedError() }
}
private var parent: _if_<T>? = null
private var elseBlock: () -> T = DEFAULT_BLOCK
infix fun _else_(elseBlock: () -> T): _if_<T> {
if (this.elseBlock != DEFAULT_BLOCK) throw IllegalStateException("multi else")
return this.apply { this.elseBlock = elseBlock }
}
infix fun _else_(_if_: _if_<T>): _if_<T> {
return _if_.also {
it.parent = this
_else_ { it.eval() }
}
}
private fun eval(): T {
return if (condition().logic()) ifBlock() else elseBlock()
}
operator fun invoke(): T {
var root: _if_<T> = this
while (root.parent != null) root = root.parent!!
return root.eval()
}
}
class _if_not_<T>(condition: () -> Any?, ifBlock: () -> T) : _if_<T>({ !condition().logic() }, ifBlock)
class _if_null_<T>(condition: () -> Any?, ifBlock: () -> T) : _if_<T>({ condition() == null }, ifBlock)
class _if_zero_<T>(condition: () -> Int, ifBlock: () -> T) : _if_<T>({ condition() == 0 }, ifBlock)
class _if_neg1_<T>(condition: () -> Int, ifBlock: () -> T) : _if_<T>({ condition() == -1 }, ifBlock)
infix fun <T> _if_<T>.`else`(elseBlock: () -> T): _if_<T> = this._else_(elseBlock)
infix fun <T> _if_<T>.`else`(_if_: _if_<T>): _if_<T> = this._else_(_if_)
typealias `if`<T> = _if_<T>
typealias `if not`<T> = _if_not_<T>
typealias `if null`<T> = _if_null_<T>
typealias `if is 0`<T> = _if_zero_<T>
typealias `if is -1`<T> = _if_neg1_<T>
/**
* (`if`({ false }) {
* 0
* } `else` `if`({ false }) {
* 1
* } `else` `if not`({ true }) {
* 2
* } `else` `if null`({ true }) {
* 3
* } `else` `if is 0`({ -1 }) {
* 4
* } `else` `if is -1`({ 0 }) {
* 5
* } `else` {
* 6
* })() -> 6
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment