Einstieg in Apples quelloffene Programmiersprache

Swift für C#-Entwickler
Kommentare

Seit der Übernahme von Xamarin durch Microsoft verfügen .NET-Entwickler über eine leistungsstarke und kostenfreie Alternative zur Entwicklung nativer Apps für iOS und OS X. Unter diesem Gesichtspunkt stellt sich die Frage, ob sich ein Blick in Richtung Swift für C#-Entwickler lohnt. Windows Developer sagt „Ja!“ und liefert in diesem Artikel eine erste Einführung.

Die native Entwicklung von iOS-Apps war mit Objective-C alles andere als komfortabel. Die an Smalltalk angelehnte, objektorientierte Syntax erschwerte mit ihrem nachrichtenbasierten Ansatz vielen Ein- und Umsteigern den Einstieg in die Sprache und somit in die Entwicklung nativer Apps für iOS und OS X. Selbst kleine Aufgaben wie das Verketten von zwei Strings kann unter Objective-C bereits zu einer Herausforderung werden, wie die folgenden beiden Codezeilen zeigen.

NSString *string1 = @"Hello";
NSString *string2 = [string1 stringByAppendingString:@" world"];

Selbstverständlich war man sich auch im Haus Apple der Problematik der hohen Einstiegshürde bewusst. Als Antwort darauf stellte man mit Swift während der Apple Worldwide Developers Conference (WWDC) im Sommer 2014 eine alternative Programmiersprache zur Entwicklung für iOS und OS X vor. Dabei handelt es sich um eine komplett neue Programmiersprache, die Apple seit 2010 intern entwickelt hat. Laut Chris Lattner, dem Architekten der Sprache, ließ man sich beim Design von Swift von Sprachen wie Objective-C, Haskell, Ruby, Python und C# inspirieren. Die primären Ziele dieser neuen Sprache sind laut Apple:

  • Eine leichte Erlernbarkeit durch eine moderne Syntax
  • Hohe Performance, da bestehende Sprachen wie C oder Objective-C durch Swift ersetzt werden sollen
  • Hohe Stabilität durch strikte Typisierung
  • Interoperabilität mit bestehendem Objective-C-Code

Auf die erste Veröffentlichung folgte mit Version 2.0 ein weiteres Major-Release, das im Juni 2015 ebenfalls auf der WWDC vorgestellt wurde. Im Dezember 2015 stellte Apple Swift unter eine Apache-2.0-Open-Source-Lizenz und veröffentlichte den Quellcode auf GitHub. Die aktuelle Version von Swift ist 2.3, das nächste Major-Release 3.0 wird noch im Jahr 2016 erwartet.

Verfügbarkeit und Werkzeuge

Die erste Swift-Version stand lediglich für Mac OS X zur Verfügung. Die Verteilung der Programmiersprache erfolgte über ein Update der hauseigenen Entwicklungsumgebung Xcode. Seit Version 2.0 gibt es auch eine Portierung für Linux. Diese umfasst den Swift-Compiler, die Swift-Standardbibliothek, die Swift Core Library sowie den Debugger. Eine integrierte Entwicklungsumgebung (IDE) fehlt unter Linux genauso wie eine Oberflächenbibliothek.

Eine Swift-Portierung für Windows gibt es aktuell nicht. Laut Apple steht diese derzeit auch nicht im Fokus, jedoch sei man offen dafür, eine Portierung aus der Community in das Swift-Haupt-Repository zu übernehmen.

Da eine komfortable Entwicklung mit Swift auf dem heutigen Stand nur auf einem Mac möglich ist, gelingt der Einstieg in Apples Programmiersprache am besten durch das Experimentieren in Xcode Playgrounds. Dabei handelt es sich um eine Funktion in der Programmierumgebung Xcode, die es erlaubt, Quellcodeschnipsel live auszuprobieren, ohne zuvor ein Projekt anlegen zu müssen. Das Ergebnis einer Quelltexteingabe wird ohne weiteres Zutun sofort in der rechten Spalte des Playgrounds angezeigt (Abb. 1).

Abb. 1: Xcode-Playgrounds erlauben schnelle Swift-Experimente

Abb. 1: Xcode-Playgrounds erlauben schnelle Swift-Experimente

Variablen und Datentypen

Die erste Berührung mit Swift läuft für C#-Entwickler relativ schmerzlos ab. Bereits beim Deklarieren von Variablen fällt auf, dass Swift auf den ersten Blick ein wenig wie modernes C# aussieht. So werden Variablen genau wie unter C# mit dem va-Schlüsselwort deklariert. Der Datentyp der Variablen muss während der Deklaration nicht angegeben werden, sofern er sich aus dem zugewiesenen Wert ergibt, wie folgende Zeilen zeigen:

var meinInteger = 42  // Int
var meinDouble = 10.2 // Double
var meinBoolan = true // Bool
var meinString = "Hallo" // String

Trotz der fehlenden expliziten Typangabe ist Swift eine typsichere Programmiersprache. Eine deklarierte Variable kann ihren Typ also nicht zur Laufzeit ändern. Somit wäre die Zuweisung des Werts true an die Variable meinInteger des vorherigen Beispiels nicht zulässig. Den Vorgang der Ermittlung des Datentyps durch den Compiler nennt man Typinferenz (Type Inference). Er funktioniert unter Swift genauso wie unter C#.

Die explizite Angabe des Datentyps sieht unter Swift hingegen allerdings etwas anders aus als unter C#. Anstatt das Schlüsselwort var durch den konkreten Datentypen zu ersetzen, erfolgt die explizite Typisierung unter Swift durch eine Typannotation:

var einBool: Bool = true
var nochEinBool: Bool

Wie die beiden vorherigen Quelltextzeilen gezeigt haben, erfolgt die Typannotation durch einen Doppelpunkt nach dem Variablennamen, gefolgt von einem Leerzeichen und dem gewünschten Datentyp. Ein Initialwert kann optional nach dem Datentyp angegeben werden.

Jeder, der schon einmal unter TypeScript programmiert hat, wird diese Schreibweise kennen. Unter TypeScript funktioniert sowohl die explizite als auch die implizite Angabe des Datentyps während der Deklaration genau gleich.

Falls Sie die letzten beiden Quellcodeschnipsel aufmerksam gelesen haben, ist Ihnen sicherlich eine weitere Eigenheit von Swift aufgefallen: Am Zeilenende muss kein Semikolon stehen. Sollten Sie sich als C#-Entwickler jedoch bereits so sehr an Semikolons gewöhnt haben, dass Sie auch unter Swift nicht auf sie verzichten möchten, dann ist auch das kein Problem. Obwohl Semikolons in der Regel nicht genutzt werden müssen, steht Ihnen die Option frei. Sie können das Semikolon am Zeilenende also ganz nach Lust und Laune setzen oder eben auch weglassen. Zwingend notwendig ist das Semikolon übrigens, wenn Sie mehr als eine Anweisung in einer Zeile unterbringen möchten:

var x = 1; println(x)

Neben Variablen ermöglicht Swift auch die Deklaration von Konstanten mithilfe des Schlüsselworts let:

let pi = 3.14159  // kann später nicht mehr geändert werden.

Let funktioniert ähnlich wie var. Der Datentyp muss also auch bei let nicht explizit angegeben werden, sondern kann durch den Compiler ermittelt werden. Der einzige Unterschied zwischen let und var besteht darin, dass der zugewiesene Wert nicht mehr verändert werden kann – schließlich handelt sich um eine Konstante. Außerdem muss die Konstante bereits während der Deklaration zwingend initialisiert werden; eine nachträgliche Initialisierung ist nicht erlaubt.

Die bisher in den Beispielen deklarierten Variablen und Konstanten wurden mit dem Sichtbarkeitsmodifizierer übrigens implizit internal ausgezeichnet. Das bedeutet, dass aus jedem Typ innerhalb des aktuellen Moduls auf sie zugegriffen werden kann. Neben internal, das wie gesagt der Standard ist, gibt es noch public und private, die sich unter Swift ähnlich verhalten wie unter C#. Die explizite Angabe eines Sichtbarkeitsmodifizierers erfolgt über ein der Deklaration vorangestelltes Schlüsselwort:

private var einePrivateVariable = "ich bin nur innerhalb meiner Quellcodedatei sichtbar"
internal var eineInterneVariable = "ich bin innerhalb des ganzen Moduls sichbar"
public var eineOeffentlicheVariable = "ich bin überall sichtbar"

Umgang mit nicht vorhandenen Werten

Einer der häufigsten Laufzeitfehler in Anwendungen jeglicher Art ist sicherlich der Zugriff auf eine Variable, die den Wert null hat. Vermutlich hat jeder C#-Entwickler bereits die gefürchtete NullReferenceException in seinem Programm gesehen und sich anschließend unzählige Stunden auf die Suche nach dem Objekt gemacht, das den Wert null hat.

Im Design der Programmiersprache Swift wurde sehr viel Wert auf Sicherheit und somit auf die Vermeidung der berühmt-berüchtigten NullReferenceExceptions gelegt. Aus diesem Grund ist es erst einmal nicht möglich, einer Variablen den Wert nil, wie null von Swift heißt, zuzuweisen. Folgende Zeilen sind also nicht gültig:

var einString: String
einString = nil

So komfortabel und sicher diese Vorgehensweise auch ist, gibt es in der Praxis jedoch trotzdem Fälle, in denen eine Variable tatsächlich den Wert null bzw. nil haben darf. Natürlich lässt sich dies auch unter Swift umsetzen, jedoch müssen Variablen bei der Deklaration explizit als optional gekennzeichnet werden. Dies geschieht über ein an den Datentyp angehängtes Fragezeichen:

Var einString: String?
einString = nil

Zur Laufzeit gibt es nun verschiedene Möglichkeiten, zu prüfen, ob ein solcher optional einen Wert hat. Der naheliegende Weg führt über eine if-Anweisung, die auf nil prüft. Hat die Variable nicht den Wert nil, so kann über ein an den Variablennamen angehängtes Ausrufezeichen direkt auf den Wert zugegriffen werden:

if einString != nil {
  print(einString!)
}

Der Zugriff auf den darunterliegenden Wert über ein Ausrufezeichnen nennt sich Forced Unwrapping. Da diese Technik auch ohne eine vorherige Prüfung auf nil möglich ist, ist sie mit Vorsicht zu genießen, da es bei ungeprüfter Anwendung zu Laufzeitfehlern kommen könnte.

Schnell und überall: Datenzugriff mit Entity Framework Core 2.0

Dr. Holger Schwichtenberg (www.IT-Visions.de/5Minds IT-Solutions)

C# 7.0 – Neues im Detail

Christian Nagel (CN innovation)

Sicherer und komfortabler ist dagegen das so genannte Optional Binding. Bei dieser Technik wird im Rahmen einer if– oder while-Anweisung der zugrunde liegende Wert, sofern vorhanden, einer temporären Konstante zugewiesen, mit der innerhalb des Blocks weitergearbeitet werden kann:

if let tempString = einString {
  print(tempString)
}

Kontrollfluss

Wie Sie im vorherigen Abschnitt gesehen haben, verfügt Swift über eine if-Verzweigung. Diese funktioniert ähnlich wie unter C#, allerdings muss die Bedingung der Verzweigung nicht durch runde Klammern umschlossen werden. Darüber hinaus gibt es unter Swift auch das switch-Schlüsselwort. Im einfachsten Fall funktioniert ein switch unter Swift genauso wie unter C# (Listing 1). Auffallend ist lediglich, dass keine break-Anweisung am Ende eines case-Zweigs notwendig ist. Das liegt daran, dass unter Swift das Konzept des „Fall-through“ – also des „Durchfallens“ von einem Zweig in den nächsten – nicht der Standard ist. Anstatt am Ende des Zweigs über break explizit anzugeben, dass nicht durchgefallen werden soll, muss unter Swift der Wunsch durchzufallen explizit über das Schlüsselwort fallthrough angegeben werden.

let dayOfWeek = 1
switch dayOfWeek{
case 1:
  print("Montag")
case 2:
  print("Dienstag")
case 3:
  print("Mittwoch")
case 4:
  print("Donnerstag")
case 5:
  print("Freitag")
case 6:
  print("Samstag")
case 7:
  print("Sonntag")
default:
  print("Mehr Tage gibt es nicht")
}

Eine weitere Besonderheit von Swifts switch-Anweisung ist die einfache Möglichkeit, Intervalle über zwei Punkte anzugeben, wie Listing 2 zeigt.

let dayOfWeek = 1
switch dayOfWeek{
case 1..5:
  print("Wochentag")
case 6..7:
  print("Wochenende")
default:
  print("Mehr Tage gibt es nicht")
}

Selbstverständlich kennt Swift nicht nur Verzweigungen, sondern auch Schleifen. In dieser Kategorie sind zum Beispiel die kopfgesteuerte while-Schleife sowie die fußgesteuerte repeat-while-Schleife vertreten. Abgesehen von der fehlenden Klammerung und der Nutzung von repeat statt do zum Einleiten einer fußgesteuerten Schleife, funktionieren diese genauso wie unter C# (Listing 3).

// Kopfgesteuert
var dayOfWeek = 1
let days = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
while dayOfWeek < days.count {
  print(days[dayOfWeek-1])
  dayOfWeek += 1
}

// Fußgesteuert
dayOfWeek = 1

repeat  {
  print(days[dayOfWeek-1])
  dayOfWeek += 1
} while dayOfWeek < days.count

Soll während einer Schleife eine Laufvariable hochgezählt werden, so kann dies unter Swift mit einer for-Schleife bewerkstelligt werden:

for var i = 0; i < 25; i++ {
  x = i*i
}

Diese Form der for-Schleife, die aus vielen anderen Programmiersprachen bekannt sein dürfte, wird in zukünftigen Swift-Versionen jedoch nicht mehr unterstützt werden. Apple empfiehlt stattdessen die for-in-Schleife, die auf Semikolons verzichtet:

for var i in 0...24 {
  x = i*i
}

Funktionen

Wiederverwendbarer Quellcode, der außerhalb von Klassen lebt, kann unter Swift durch Funktionen ausgedrückt werden. Funktionen müssen unter Swift keinen Wert zurückgeben. Somit unterscheiden sie sich von den Funktionen unter C#, die stets einen Wert zurückgeben. Die Deklaration einer Funktion erfolgt mittels des func-Schlüsselworts (Listing 4).

// Deklaration der Funktion printDayOfWeek
func printDayOfWeek(day: Int){
  let days = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
    print(days[day-1])
}

// Aufruf der Funktion
printDayOfWeek(1)

Gibt die Funktion Werte zurück, wird dies über die Angabe des Datentyps nach einem vorangestellten Rückgabepfeil (->) erreicht (Listing 5).

// Deklaration der Funktion getDayOfWeek
func getDayOfWeek(day: Int) -> String{
  let days = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
  return days[day-1]
}

// Aufruf der Funktion
print(getDayOfWeek(1))

Klassen

Als objektorientierte Sprache kennt auch Swift das Konstrukt von Klassen. Wie in den meisten anderen Programmiersprachen auch, werden Klassen über das Schlüsselwort class definiert. Eigenschaften werden – sofern sie keine eigene Logik haben – unter Swift einfach als Feld angelegt. Konstruktoren werden über das Schlüsselwort init eingeleitet (Listing 6).

class Person{
  var firstName: String // Read-/Write-Eigenschaft der Klasse Person
  var lastName: String // Read-/Write-Eigenschaft der Klasse Person

  // Konstruktor
  init(firstName: String, lastName: String){
    self.firstName = firstName
    self.lastName = lastName
  }

  // Read-Only Eigenschaft
  var fullName: String{
    return firstName + " " + lastName
  }
}

// Erzeugen eines neuen Objekts der Klasse Person.
var p = Person(firstName: "Wilhelm", lastName: "Brause")
print(p.fullName)

Ungewohnt für C#-Entwickler dürfte die vorletzte Zeile aus Listing 6 sein. Unter Swift wird bei der Erzeugung eines neuen Objekts kein Gebrauch des Schlüsselworts new gemacht. Stattdessen wird die Klasse ähnlich einer Funktion aufgerufen, mit der Besonderheit, dass die Parameternamen im Konstruktoraufruf mit angegeben werden müssen.

Weiter dürfte es den meisten C#-Entwicklern merkwürdig erscheinen, dass Eigenschaften einer Klasse anscheinend als simple Felder deklariert werden. Dass dieser Eindruck trügt, zeigt Listing 7. Über so genannte Property Observer lassen sich solche einfachen Felder unter Swift tatsächlich zu vollwertigen Feldern ausbauen – in den Augen des C#-Entwicklers.

class Person{
  var firstName: String {
  willSet(value) {
    print("Eigenschaft firstName wird verändert")
  }
  didSet {
    if(firstName != oldValue){
      print("Eigenschaft firstName wurde verändert")

    }
  }

  }
  var lastName: String
  // Weiterer Quellcode der Klasse wurde gekürzt
}

// Erzeugen eines neuen Objekts der Klasse Person.
var p = Person(firstName: "Wilhelm", lastName: "Brause")
p.firstName = "Hans"  // lost die Property-Observer aus.
print(p.fullName)

Wie Listing 8 zeigt, ist das Konzept der Vererbung unter Swift ganz ähnlich wie unter C# umgesetzt: über einen Doppelpunkt, der die abgeleitete Klasse und Basisklasse voneinander trennt.

// Deklaration der abgeleiteten Klasse Employee
class Employee: Person{
  var employeeId = 0;

  // Konstruktor
  init(firstName: String, lastName: String, employeeId: Int){
    super.init(firstName: firstName, lastName: lastName)
      self.employeeId = employeeId
  }

  // Überschriebene Methode
  override var fullName: String{
    return super.fullName + ", Mitarbeiter Nummer: \(self.employeeId)"
  }
}

// Erzeugung und Nutzung der abgeleiteten Klasse
var e = Employee(firstName: "Wilhelm", lastName: "Brause", employeeId: 10)
print(e.fullName)
print(e.employeeId)

Fazit

Apple hat mit Swift eine moderne Programmiersprache auf den Markt gebracht. Man merkt der Sprache an, dass sie die Stärken von Objective-C mit denen aktueller Programmiersprachen vereint. Die Entwicklung mit Swift geht in der Praxis recht leicht von der Hand und lässt sich – im Unterschied zu Objective-C – als sehr angenehm beschreiben.

Wie die im Artikel aufgeführten Codebeispiele gezeigt haben, ist die Ähnlichkeit zu C# recht hoch. Einige Konstrukte unterscheiden sich jedoch sehr, wie zum Beispiel die Deklaration von Konstanten oder die Definition von Eigenschaften und Konstruktoren in Klassen. Daher kann es als C#-Entwickler nicht schaden, einen Blick in die offizielle Dokumentation von Swift zu werfen, ehe man in die Entwicklung mit Swift einsteigt.

Selbst wenn man nicht aktiv mit Swift entwickeln möchte, da man im Bereich der App-Entwicklung auf Xamarin zurückgreift, lohnt sich die Beschäftigung mit der Sprache. Apples Dokumentation des iOS-API, auf das man auch als Xamarin-Entwickler gerne zurückgreift, ist zum größten Teil mit Swift-Beispielen versehen. Um es zu verstehen, sollte man sich vorab mit der Sprache beschäftigen. Gleiches gilt für Codebeispiele in Blogs oder auf Stack Overflow.

Doch auch wer nicht vorhat, in die App-Entwicklung einzusteigen, kann Vorteile aus dem Erlernen von Swift ziehen. Auf der einen Seite schadet es natürlich nie, den eigenen Horizont zu erweitern, auf der anderen Seite leben wir in einer Zeit, in der sich Programmiersprachen massiv gegenseitig inspirieren. Es wäre demnach also nicht verwunderlich, wenn das ein oder andere Swift-Feature Einzug in eine zukünftige C#-Version halten würde.

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist der Windows Developer ferner im Abonnement oder als Einzelheft erhältlich.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -