Standardwerte für Parameter
Die Programmiersprache Swift liegt heute bereis in Version 5.7 vor und hat bereits einen weiten Weg hinter sich. In all den Jahren, in denen Swift inzwischen zur Verfügung steht, wurde die Sprache stetig verbessert und weiterentwickelt.
Ich selbst nutze Swift seit Version 1 und es gibt so einiges, das mir an dieser Sprache immens gut gefällt. Diese neue Artikelreihe soll euch – aus meiner ganz persönlichen Sicht – einige dieser Features vorstellen.
Dabei geht es mir nicht um die aufwendigsten oder modernsten Funktionen. Es spielt auch keine Rolle, ob ein Feature von Beginn an existierte oder erst in einer späteren Version hinzukam. Es handelt sich schlicht um einen persönlichen Auszug dessen, was mir bei der Arbeit mit Swift besondere Freude bereitet.
Starten möchte ich mit einem Feature, das ich persönlich sehr exzessiv nutze und das in meinen Augen massiv zu sauberem und übersichtlichen Code in Swift-Projekten beitragen kann: Standardwerte für Parameter (die sogenannten Default Parameter Values).
Ausgangslage
Lasst mich die Schönheit dieses Features direkt einmal anhand eines simplen Beispiels demonstrieren. Gegeben ist die Klasse User
, die den Anwender einer App abbildet. Neben einem eindeutigen username
, der für jede User
-Instanz zu setzen ist, bringt die Klasse auch noch diverse optionale Eigenschaften mit sich. Dazu gehören Properties zum Abbilden von Vor- und Nachname und dem Geburtstag des Nutzers. Außerdem wird über die access
-Eigenschaft festgelegt, ob ein Nutzer Vollzugriff auf alle Funktionen hat (pro
) oder nur die Standard-Funktionen verwenden kann (standard
).
class User {
enum Access {
case standard
case pro
}
var username: String
var access: Access
var firstName: String?
var lastName: String?
var birthday: Date?
init(username: String, access: Access) {
self.username = username
self.access = access
}
init(username: String, access: Access, firstName: String?, lastName: String?, birthday: Date?) {
self.username = username
self.access = access
self.firstName = firstName
self.lastName = lastName
self.birthday = birthday
}
}
Bei der Initialisierung müssen in jedem Fall Werte für username
und access
übergeben werden, da diese Parameter nicht optional sind. Entsprechend bringt die Klasse User
einen passenden Initializer namens init(username:access:)
mit. Zusätzlich sollen aber auch nach belieben Werte für die anderen Eigenschaften bei der Initialisierung gesetzt werden können (abhängig davon, ob entsprechende Informationen vorliegen). Zu diesem Zweck steht ein zweiter Initializer namens init(username:access:firstName:lastName:birthday:)
zur Verfügung. Die Parameter für die optionalen Eigenschaften sind auch in diesem Initializer als optional deklariert.
Umsetzung und Nutzen von Default Parameter Values
Technisch gesehen gibt es an der Klasse User
nichts auszusetzen. Die Initialisierung kann sich jedoch teils als umständlich erweisen.
Das beginnt bereits beim Einsatz von init(username:access:)
. Wenn wir davon ausgehen, dass die meisten Nutzer nur die Standard- und nicht die Pro-Funktionen nutzen, muss dennoch bei der Initialisierung immer der entsprechende standard
-Wert für access
übergeben werden. Schöner wäre es, diesen Wert standardmäßig für den access
-Parameter zu nutzen. Und genau das lässt sich in Swift realisieren, wie die folgende Anpassung des Initializers demonstriert:
init(username: String, access: Access = .standard) {
self.username = username
self.access = access
}
Durch schlichte Zuweisung eines Werts nach der Angabe des zugehörigen Parameter-Typs definiert man diesen Wert als Standard. Die folgenden zwei Aufrufe dieses Initializers sind nun identisch und führen zum selben Ergebnis:
let firstUser = User(username: "First")
let secondUser = User(username: "Second", access: .standard)
Für den Zugriff auf die Standard-Funktionen muss also nicht länger explizit der standard
-Wert für den access
-Parameter bei der Initialisierung gesetzt werden (es ist aber natürlich auch kein Fehler, ihn trotzdem mit anzugeben). Nur in dem Fall, dass pro
für access
zu verwenden ist, muss dieser Wert auch entsprechend übergeben werden:
let proUser = User(username: "Pro", access: .pro)
Ähnlich lässt sich nun auch der zweite Initializer init(username:access:firstName:lastName:birthday:)
optimieren. Denn auch der hat einen Nachteil (neben dem noch fehlenden Standardwert für access
): Setzt man beispielsweise nur den Vornamen, muss für lastName
und birthday
trotzdem jeweils nil
übergeben werden, was den Aufruf dieses Initializers unnötig aufbläht:
let firstUser = User(username: "First", access: .standard, firstName: "Thomas", lastName: nil, birthday: nil)
Zur Optimierung kann man deshalb festlegen, dass die optionalen Parameter standardmäßig nil
entsprechen. Zusätzlich weist man access
noch den Standardwert standard
zu:
init(username: String, access: Access = .standard, firstName: String? = nil, lastName: String? = nil, birthday: Date? = nil) {
self.username = username
self.access = access
self.firstName = firstName
self.lastName = lastName
self.birthday = birthday
}
Der vorherige Initializer-Aufruf lässt sich nun wie folgt abkürzen:
let firstUser = User(username: "First", firstName: "Thomas")
Das entschlackt den Code deutlich und macht ihn übersichtlicher. Gleichzeitig können wir uns mit dieser Anpassung des zweiten Initializers nun den ersten Initializer vollständig sparen! Da es für all die zusätzlichen Parameter des zweiten Initializers passende Standardwerte gibt, lässt der sich genau so verwenden wie init(username:access:)
. Die Klasse Person
wird dadurch auch noch mal etwas schlanker:
class User {
enum Access {
case standard
case pro
}
var username: String
var access: Access
var firstName: String?
var lastName: String?
var birthday: Date?
init(username: String, access: Access = .standard, firstName: String? = nil, lastName: String? = nil, birthday: Date? = nil) {
self.username = username
self.access = access
self.firstName = firstName
self.lastName = lastName
self.birthday = birthday
}
}
Fazit
Ich bin ein großer Fan von Standardwerten für Parameter in Swift. Wie bereits dieses simple Beispiel der User
-Klasse gezeigt hat, lässt sich damit einerseits der benötigte Code verschlanken, da nicht mehr mehrere verschiedene Varianten mit unterschiedlichen Parametern für eine Funktion benötigt werden. Gleichzeitig lassen sich auch die Funktionsaufrufe vereinfachen, wenn nur jene Werte gesetzt werden müssen, die notwendig sind und nicht in dem meisten Fällen einem expliziten Wert entsprechen (wie im Falle von access
, für das meist standard
zum Einsatz kommt).
Natürlich sollte man es aber auch mit den Default Parameter Values nicht übertreiben. Sie sollten wirklich nur dann zum Einsatz kommen, wenn ein bestimmter Wert als Standard für einen Parameter angesehen werden kann. Dann sind sie aber in jedem Fall eine große Hilfe und tragen zur Optimierung und Übersichtlichkeit des eigenen Codes bei.
Euer Thomas
Schreibe einen Kommentar