Skip to content

Commit

Permalink
Added Kotlin Contracts (#41)
Browse files Browse the repository at this point in the history
* Added contracts for ifExtensions

* Updated version

* Improved test case

Co-authored-by: tvkanters <tvkanters@gmail.com>
  • Loading branch information
TimonKanters-TomTom and tvkanters committed Feb 23, 2022
1 parent 89c5c50 commit 6f4436c
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 11 deletions.
5 changes: 5 additions & 0 deletions README.md
Expand Up @@ -659,6 +659,11 @@ Contributors: Timon Kanters, Jeroen Erik Jensen, Krzysztof Karczewski

## Release notes

### 1.6.3

* Added [Kotlin Contracts](https://github.com/Kotlin/KEEP/blob/master/proposals/kotlin-contracts.md) to `ifTrue` and
`ifNull`.

### 1.6.2

* Removed cast extensions.
Expand Down
2 changes: 1 addition & 1 deletion extensions/pom.xml
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.2</version>
<version>1.6.3</version>
</parent>

<artifactId>extensions</artifactId>
Expand Down
Expand Up @@ -16,6 +16,10 @@

package com.tomtom.kotlin.extensions

import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

/**
* Executes [block] if `this` is `true`, and returns the result. If `this` is `false` or `null`, it
* returns `null`.
Expand All @@ -32,11 +36,17 @@ package com.tomtom.kotlin.extensions
* someCondition.ifTrue { someValue }
* ```
*
* It may be inefficient to invert the logic to `someValue.takeIf { someCondition }` when
* `someValue` isn't readily available.
* This is useful when it is not efficient to invert the logic to
* `someValue.takeIf { someCondition }` when `someValue` isn't readily available.
*/
public inline fun <T> Boolean?.ifTrue(block: () -> T): T? =
if (this == true) block() else null
@OptIn(ExperimentalContracts::class)
public inline fun <T> Boolean?.ifTrue(block: () -> T): T? {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
returnsNotNull() implies (this@ifTrue != null)
}
return if (this == true) block() else null
}

/**
* Returns `this` if it is not null. Otherwise, it executes [block] and returns the result.
Expand Down Expand Up @@ -72,5 +82,10 @@ public inline fun <T> Boolean?.ifTrue(block: () -> T): T? =
* chain-calling constructs however, the Elvis operator can easily lead to reduced readability.
* `let` helps with this, but adds boilerplate that distracts from the functional flow.
*/
public inline fun <T> T?.ifNull(block: () -> T) : T =
this ?: block()
@OptIn(ExperimentalContracts::class)
public inline fun <T> T?.ifNull(block: () -> T): T {
contract {
callsInPlace(block, InvocationKind.AT_MOST_ONCE)
}
return this ?: block()
}
Expand Up @@ -66,6 +66,26 @@ internal class IfExtensionsTest {
verify(exactly = 0) { ifTrueBlock.invoke() }
}

@Test
fun `ifTrue contract returnsNotNull`() {
// GIVEN
val sut: Boolean? = null

@Suppress("unused")
fun Any.callOnNonNull() {}

// WHEN ifTrue returns something other than null
if (sut.ifTrue { 1 } != null) {

// THEN no null-check is needed on sut
sut.callOnNonNull()
} else {

// AND in else it requires a null-check with ?
sut?.callOnNonNull()
}
}

@Test
fun `ifNull on null`() {
// GIVEN
Expand Down
2 changes: 1 addition & 1 deletion memoization/pom.xml
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.2</version>
<version>1.6.3</version>
</parent>

<artifactId>memoization</artifactId>
Expand Down
3 changes: 2 additions & 1 deletion pom.xml
Expand Up @@ -22,7 +22,7 @@

<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.2</version>
<version>1.6.3</version>
<packaging>pom</packaging>

<name>Kotlin Tools</name>
Expand Down Expand Up @@ -231,6 +231,7 @@
<configuration>
<args>
<arg>-Xexplicit-api=strict</arg>
<arg>-Xopt-in=kotlin.RequiresOptIn</arg>
</args>
</configuration>
</plugin>
Expand Down
2 changes: 1 addition & 1 deletion traceevents/pom.xml
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.2</version>
<version>1.6.3</version>
</parent>

<artifactId>traceevents</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion uid/pom.xml
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>com.tomtom.kotlin</groupId>
<artifactId>kotlin-tools</artifactId>
<version>1.6.2</version>
<version>1.6.3</version>
</parent>

<artifactId>uid</artifactId>
Expand Down

0 comments on commit 6f4436c

Please sign in to comment.