with(Kotlin)

Le langage Kotlin dispose d'une fonction pratique appelée with, qui permet de regrouper des appels sur une même référence, ce qui évite de répéter celle-ci.

Ainsi, les lignes de code ci-après :

1
2
3
user.username = "Alice"
user.addFriend("Bob")
...

peuvent être remplacées par les suivantes, en utilisant la fonction with :

1
2
3
4
5
with(user) {
    username = "Alice"
    addFriend("Bob")
    ...
}

Voyons comment la fonction with est définie et implémentée dans Kotlin :

1
2
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

Un peu compliquée à première vue, non ? Eh bien, with exécute la fonction block sur le receveur receiver de type T, le type T étant en fait étendu par l'expression lambda block (syntaxe T.).

Dans l'exemple de code plus haut, la fonction with est bien appelée avec deux paramètres : la référence user, suivie d'un bloc.

Voici un exemple complet :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
fun main(args: Array<String>) {

    class User(var username: String) {
        fun addFriend(friend: String) {}
    }

    val user = User("Bertrand")
    // ...
    val result = with(user) {
        username = "Alice"
        addFriend("Bob")
        "ok"
    }

    assert(user.username == "Alice")
    assert(result == "ok")
}

A titre de comparaison, voici comment ce bout de code pourrait se traduire dans le langage Groovy (toutefois pas de manière complètement exacte), avec l'utilisation de la méthode with qui étend le type Object :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User {
    String username
    def addFriend(String friend) {}
}

def user = new User(username: 'Bertrand')
// ...
def result = user.with {
    username = 'Alice'
    addFriend 'Bob'
    'ok'
}

assert user.username == 'Alice'
assert result == 'ok'