Découverte de Swift

Publié le 18 juin 2014 par Nicolas Cavigneaux | back

Cet article est publié sous licence CC BY-NC-SA

Dans cet article je vais tenter de donner mon ressenti sur les quelques jours que j’ai passé à tester le nouveau langage d’Apple, Swift.

Tout d’abord il faut savoir que j’ai eu l’occasion d’écrire des applications OS X / iOS en Objective C mais aussi en RubyMotion. J’ai donc forcément tendance à comparer le langage Swift et les possibilités qu’il propose à ces deux autres langages / toolchains que je connais déjà.

Swift est présenté par Apple comme étant un langage innovant pensé pour utilisation avec Cocoa. Le but est de proposer un langage plus concis, facile d’accès et moderne. Il peut tout à fait être utilisé en parallèle d’Objective C comme vous le feriez avec RubyMotion par exemple. Le dernier argument utilisé par Apple pour pousser Swift est qu’il serait particulièrement rapide à l’exécution.

Syntaxe basique

Je vais tout d’abord vous montrer quelques exemples de code très simples mais qui vous donneront une idée très précise de ce qu’est Swift.

Contrairement à RubyMotion, Swift est un langage typé ce qui est loin d’être un détail. Bien qu’il soit tout à fait possible de ne pas utiliser ce typage explicite dans la plupart des cas, c’est un élément central du langage.

Certains aimeront et trouveront même que c’est indispensable, d’autre au contraire penseront que c’est un frein au développement. C’est une question de goûts et d’habitudes je ne rentrerais donc pas dans une polémique à ce sujet.

Finalement vous noterez dans les exemples que Swift ne requiert pas l’utilisation d’un caractère marquant la fin d’une instruction comme le point-virgule par exemple. Comme en Ruby, vous vous en passerez dans la grande majorité des cas mais il reste possible de l’utiliser si vous voulez écrire plusieurs instructions sur la même ligne.

Variables et constantes

Deux mots-clés dédiés permettent de définir variables et constantes. Les variables sont définies avec le mot clé var. Les constantes utilisent elles le mot clé let.

Les variables récupérées via les paramètres de fonction sont auto-déclarées via let mais il reste possible d’en faire des variables.

var str = "Hello Swift"
var i = 12

var label = str + String(i)

var interpolation = "\(str) \(i)"

var array = ["foo", "bar", "baz"]
array[1]

var dict = [
    "foo": "Foo",
    "bar": "Bar",
    "baz": "Baz"
]
dict["baz"]

Il est également possible de typer les variables ou encore de préciser qu’elle seront potentiellement nulles :

var optionalString: String? = "Hello"
optionalString = nil

var optionalName: String? = "Nico"
var greeting = "Hello!"

if let name = optionalName {
    greeting = "Hello, \(name)"
}

Comme vous pouvez le voir, l’interpolation des variables au sein d’une chaîne se fait via \(la_variable). Vous remarquerez également que nous créons une constante à la volée dans le if.

Déclaration et utilisation de fonctions

Créons une fonction qui prendra deux paramètres, le premier étant une chaîne et le second un booléen.

Notre fonction devra retourner une chaîne différente en fonction du booléen.

func greet(name: String, specialOffer: Bool) -> String {
    var greeting = "Hello, \(name)"

    if specialOffer {
        greeting += ", today special offer"
    }

    return greeting
}

greet("Nico", true)

Créons maintenant un fonction averageOf qui aura pour but de … calculer une moyenne. Elle devra prendre un nombre variable d’entiers en entrée et retourner un nombre à virgule.

func averageOf(numbers: Int...) -> Double {
    var sum = 0
    for n in numbers {
        sum += n
    }

    var avg = sum / numbers.count
    return Double(avg)
}

averageOf(2, 4)

Le nombre d’arguments variable est définie grâce au ... qui peut être comparé au splat en Ruby.

Déclaration de classe

class Person {
    var name: String

    init(name: String = "John Doe") {
        self.name = name
    }

    func introduction() -> String {
        return "Hello I'm \(name)"
    }

    class func description() {
        return "This class creates human beings!"
    }
}

Person.description()

var unknown = Person()
unknown.introduction()

unknown.name = "Nobody"
unknown.introduction()

var nico = Person(name: "Nico")
nico.introduction()

Nous créons donc une classe Person qui possède une variable d’instance name.

Nous déclarons un constructeur via init qui attend un paramètre name facultatif. Si ce paramètre est omis, il sera initialisé à “John Doe”. Cette méthode d’initialisation va utiliser le paramètre passé pour initialiser la variable d’instance name qui représente le nom de la personne.

Une méthode d’instance est ensuite déclarée via le mot-clé func. Cette méthode ne prend pas de paramètres en entrée et retourne une chaîne.

Finalement nous ajoutons une méthode de classe, appelées type methods dans la terminologie de Swift. Elle n’a d’autre intérêt que de vous montrer comment déclarer une méthode de classe.

Nous utilisons ensuite cette classe de deux façons différentes. Dans le premier cas, nous instancions la classe sans passer de paramètre. name vaut donc “John Doe”. Nous modifions ensuite l’attribut name grâce à la syntaxe .name = très classique. Finalement nous instancions un nouvel objet, cette fois en passant le name directement en paramètre.

Comme vous pouvez le remarquer, pour instancier une classe, nul besoin de faire un new Person() ou autre syntaxe particulière, il suffit d’appeler la classe comme une fonction pour qu’elle soit instanciée.

Héritage

Pour déclarer une classe héritant d’une autre il faut utiliser la syntaxe class Enfant: Parent.

class Child: Person {
    var favoriteGame: String

    init(name: String, favoriteGame: String) {
        self.favoriteGame = favoriteGame
        super.init(name: name)
    }

    override func introduction() -> String {
        return "Hi! I'm \(name)"
    }

    func play() -> String {
        return "Wanna play \(favoriteGame)!"
    }
}

var child = Child(name: "Bobby", favoriteGame: "video games")
child.introduction()
child.play()

Dans notre exemple nous déclarons une variable d’instance supplémentaire favoriteGame. Le constructeur est redéfini pour prendre en compte les spécificités de la nouvelle classe puis appelle ensuite le constructeur parent pour l’initialisation des éléments en commun.

Nous modifions également le comportement de la méthode introduction. Pour ce faire nous devons préciser que nous écrasons la méthode de la classe parent grâce au mot-clé override qui est en quelque sorte une mesure de sécurité pour éviter les écrasements par erreur.

Un autre exemple utilisant une variable dynamique :

class Woman: Person {
    var age: Int

    var realAge: Int {
        return age + 10
    }

    init(name: String, age: Int) {
        self.age = age
        super.init(name: name)
    }

    override func introduction() -> String {
        return "Hello! I'm \(name) and I'm \(realAge)"
    }
}

var woman = Woman(name: "Lucie", age: 27)
woman.introduction()

Nous définissons ici une variable realAge qui se base elle même sur un attribut de l’objet. Nous ne faisons donc pas d’appel de méthode pour l’utiliser mais le fonctionnement en est finalement très proche. C’est assez proche d’un attribut computed en Ember.js.

Les autres fonctionnalités intéressantes

Nous sommes loin d’avoir fait le tour du langage, de ses possibilités et spécificités. Voici quelques autres points qui me semblent particulièrement intéressants et sur lesquels vous pouvez vous documenter si Swift vous intéresse :

  • affectations multiples de variables
  • paramètres nommés
  • closures
  • enumeration

Les avantages immédiats

Ce qui est évident dès qu’on commence à tester ce langage est qu’il est bien plus accessible que de l’Objective C. Sa syntaxe est plus naturelle, plus concise. Vous n’avez pas à vous soucier de la gestion de la mémoire. Avec assez peu de pratique vous arriverez sans problème à écrire votre code, l’organiser en classe, etc.

Après l’avoir utilisé, j’ai eu l’impression d’avoir à faire face à un hybride entre du lisp, du ruby et du JavaScript. On n’est pas perdu en même temps, tout est différent mais très facile d’accès.

Le gros point fort lié à l’utilisation de Swift est le playground qui est en fait un REPL. C’est certainement la première chose que vous testerez, c’est là que vous découvrirez le langage et ferez vos expérimentations de code. Évidemment cette partie m’a directement fait penser à RubyMotion et son REPL qui permet lui aussi de tester du code ou encore d’analyser / modifier votre code et ses variables au cours de l’exécution de votre programme.

Les points noirs

Bien que le playground soit une avancée plus qu’appréciable, c’est encore très buggé. Pendant mes essais ça a régulièrement planté ce qui entrave très largement la productivité et le plaisir d’utilisation. Espérons que ces soucis seront réglés dans les versions stables à venir.

Dès lors qu’on commence à vouloir faire du “vrai” code, de nombreux problèmes pointent le bout de leur nez, il y a des comportements qui ne semblent pas normaux et homogènes. On sent bien qu’on est en beta, on ne peut clairement en douter ou l’oublier, il reste du travail avant d’avoir quelque chose de réellement utilisable et fiable.

Dernier point, il faudra bien sûr être sous OS X 10.10 pour pouvoir profiter de Swift. Dommage pour tout ceux qui ne peuvent ou veulent upgrader leur machine.

C’est vraiment plus rapide ?

L’un des plus gros argument mis en avant par Apple concernant Swift est, d’après eux, un gain impressionnant en terme de rapidité d’exécution. De l’ordre de 20%, c’est énorme.

Des benchmarks ont été fait par plusieurs personnes. On note que tous les cas d’utilisation ne présentent pas forcément de réels gains par rapport à l’équivalent en Objective C. Certains sont même plus lents. Je ne trouve pas ça étonnant puisque finalement les deux langages utilisent llvm pour produire l’exécutable et Objective C est loin d’être un langage lent.

Je pense donc qu’il ne faut pas tenir compte de potentiel gain pour choisir le langage dans lequel vous développerez votre application.

Conclusion

Ce n’est évidemment pas une revue complète du langage mais plutôt une introduction pour que vous puissiez vous faire une idée sur la syntaxe du langage et partager mon ressenti.

Si vous voulez en savoir plus, je vous conseille la documentation dédiée qui est très complète et vraiment très claire.

Cette même documentation est disponible sous forme d’iBook gratuit sur le store d’Apple. Un autre dédié à l’utilisation de Swift dans le contexte de Cocoa, en conjonction avec Objective C est lui aussi disponible gratuitement.

Il y a fort à parier que les nouveaux arrivants dans le monde du développement OS X / iOS se tourneront plus facilement vers Swift. Les habitués d’Objective C quant à eux préféreront certainement continuer à utiliser principalement ce langage par habitude mais aussi parce qu’il estimeront avoir plus de flexibilité et d’emprise sur leur code qu’avec Swift.

Les utilisateurs de solutions alternatives comme RubyMotion n’y verront que peu d’intérêt et continueront certainement d’utiliser leur toolchain habituelle. Généralement ces utilisateurs de solutions alternatives le sont parce qu’ils sont plus à l’aise avec le langage / framework en question et souhaitent conserver leurs habitudes, leur productivité en développant des applications OS X.


L’équipe Synbioz.

Libres d’être ensemble.