Meine liebsten Swift-Features – Teil 2

Trennung von Argument Label und Parameter Name

Ich schätze gute APIs. Funktionen, die einen klar verständlichen Zweck erfüllen und sich sowohl beim Aufrufen als auch bei der Implementierung gut lesen lassen, sind in meinen Augen geradezu schön. So gesehen sind für mich gute APIs solche, deren Zweck (wenigstens grundlegend) auch ohne Dokumentation ersichtlich ist und dabei über einen möglichst knappen und bezeichnenden Namen verfügen. Das gilt auch für die Parameter, die eine Funktion erwartet.

In Swift setzen sich die Parameter von Funktionen seit jeher aus zwei Elementen zusammen: das Argument Label und den Parameter Name. Das Argument Label kommt beim Aufruf der Funktion zum Einsatz, während der Parameter Name in der Implementierung der Funktion zum Zugriff auf den Wert des zugehörigen Parameters verwendet wird.

Standardmäßig sind Argument Label und Parameter Name identisch, wie das nachfolgende Beispiel demonstriert. Sie tragen die Bezeichner firstValue und secondValue.

func addition(firstValue: Int, secondValue: Int) -> Int {
    firstValue + secondValue
}

addition(firstValue: 19, secondValue: 99)

In diesem Fall spricht auch nichts gegen die identische Benennung von Argument Label und Parameter Name. Der Zweck der Funktion ist klar und die Parameter-Namen verdeutlichen das (sowohl innerhalb der Implementierung der Funktion als auch beim Aufruf).

Etwas komplizierter wird es beim nachfolgenden Beispiel. Grundlage des Codes sind die Typen Person und Group. Eine Person setzt sich aus Vor- und Nachname zusammen, während eine einzelne Group ein Array an Person-Instanzen hält.

struct Person {
    var firstName: String
    var lastName: String
}

class Group {
    var members = [Person]()
}

Nachfolgend seht ihr nun die beispielhafte Umsetzung einer Funktion, über die eine Person einer Group hinzugefügt wird.

func add(person: Person, group: Group) {
    group.members.append(person)
}

let me = Person(firstName: "Thomas", lastName: "Sillmann")
let someGroup = Group()
add(person: me, group: someGroup)

Technisch ist diese Umsetzung korrekt. Auch die Implementierung liest sich gut und ist verständlich. Der Aufruf allerdings kann verwirren. Liest man lediglich add(person: me, group: someGroup), ohne die Implementierung dieser Funktion zu kennen, fragt man sich womöglich, was genau nun geschieht. Werden Person und Gruppe irgendwo hinzugefügt oder zusammengefasst? So zumindest kann es auf den ersten Blick den Anschein haben.

Für den Aufruf würde es mehr Sinn machen, die Funktionalität über den zweiten Parameter klar zu definieren. Dazu könnte man den zweiten Parameter beispielsweise in toGroup umbenennen. Das macht den Sinn und Zweck deutlich klarer, sieht aber umgekehrt in der Implementierung der Funktion extrem unschön aus. Dort muss die Gruppe dann nämlich auch über den toGroup-Bezeichner angesprochen werden.

func add(person: Person, toGroup: Group) {
    toGroup.members.append(person)
}

add(person: me, toGroup: someGroup)

Um diese API zu optimieren, bietet sich die explizite Trennung von Argument Label und Parameter Name an. Nachfolgend kommt so weiterhin als Argument Label toGroup zum Einsatz, der Parameter Name hingegen entspricht aber wieder wie zuvor group. Sowohl Aufruf als auch Implementierung profitieren deutlich von dieser Änderung.

func add(person: Person, toGroup group: Group) {
    group.members.append(person)
}

add(person: me, toGroup: someGroup)

Man könnte hier auch noch einen Schritt weiter gehen und die API noch etwas übersichtlicher gestalten. Dazu verzichtet man für den ersten Parameter person gänzlich auf ein Argument Label und kürzt das zweite Argument Label von toGroup schlicht zu to. Das schafft beim Aufruf einen geradezu lesbaren Charakter des Befehls: Add me to someGroup. Das ist kurz und prägnant, und man kann sich sehr gut vorstellen, welchen Zweck diese Funktion erfüllt.

func add(_ person: Person, to group: Group) {
    group.members.append(person)
}

add(me, to: someGroup)

Fazit

Swifts Trennung von Argument Label und Parameter Name ist die Grundlage, um gut verständliche und kompakte Funktionsnamen zu definieren. Durch geschicktes Setzen des Argument Labels schafft man Funktionen, deren Zweck sich im Idealfall sprechend lesen lassen. Gleichzeitig greift man innerhalb der Implementierung dank des Parameter Names auf passende Bezeichner für die jeweiligen Parameter zurück.

Dieses Feature existiert bereits seit der ersten Version von Swift. Es mag nicht weltbewegend sein, schafft aber bei passender Anwendung deutlich besser lesbaren Code sowie kompakte Funktionsaufrufe.

Euer Thomas


Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert