Protocol implémenté par une classe et une structure

JérémyJérémy Membre
février 2017 modifié dans API UIKit #1

Bonjour à  tous !


Petite question du vendredi : Pouvons nous créer une implémentation par défaut spécifique aux classes et une autre spécifique aux structures ?


Exemple :

 



protocol Copyable {
    init(_: Self)
    
    func copy() -> Self
}

extension Copyable {
    func copy() -> Self {
        return init(self)
    }
}

Contrairement au classes, sur les stuctures se sont les valeurs qui primes et non les références. De ce fait, nous aurions pu écrire le code suivant pour ces dernières :

 



func copy() -> Self {
    return self
}

L'idée serait de mettre dans extension Copyable les deux implémentations par défaut.


Ceci vous parait il envisageable ? Si oui, comment faire.


Je vous remercie par avance pour vos réponses. :)


«1

Réponses

  • On peut faire quelque chose qui s'en rapproche sans forcément être très précis. Du moins à  ma connaissance.


     


    On aurait quelque chose semblable à  ça :



    protocol Test {
    func myTest()
    }

    extension Test where Self: AnyObject {
    func myTest() {
    print("Hello Class")
    }
    }

    extension Test where Self: Any {
    func myTest() {
    print("Hello NO Class")
    }
    }

    class TestClass: Test {}
    struct TestStruct: Test {}

    let myClass = TestClass()
    let myStruct = TestStruct()

    myClass.myTest()
    myStruct.myTest()

    AnyObject est un protocol auquel toutes les classes se conforment.


    Toutefois pour le protocol Any, il représente tous les types : 


     



     


     



    • Any can represent an instance of any type at all, including function types.



     


    Donc c'est pas exactement ce que tu demandes mais c'est quelque chose qui s'en rapproche.


     


    À noter que tu peux explicitement dire que ton protocol peut être implémenter seulement par des class de cette façon.



    protocol Test: class {}

    C'est très utile pour optimiser la compilation d'informer le compilateur que seules des class peuvent implémenter le protocole. C'est d'ailleurs vrai pour le choix des structures, enum ou class ou de l'encapsulation, des extensions, des propriétés et autres. ça aide à  savoir quelle méthode de Dispatch il va utiliser et donc sa performance.


  • Ah bien ! ça me va. :)


     


    Même si ce n'est pas exactement ce que je veux, ta proposition a le mérite d'apporter une bonne réponse à  ce que je cherche à  faire.


     


     



    À noter que tu peux explicitement dire que ton protocol peut être implémenter seulement par des class de cette façon.

    protocol Test: class {}



     


    Existe t'il un mécanisme similaire pour les structures ?


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #4

    Il n'y a pas de différence quand tu copies un classe ou une struct.


     


    Mais si tu veux utiliser ce code dans une struct :



    func copy() -> Self
    {
    return self
    }

    ... il ne revoie que la même référence. Ce n'est que sur la modification d'une struct que la référence change.


     


    Et, si tu utilises ton protocol avec une classe :



    protocol Copyable
    {
    func copy() -> Self

    init(other: Self)
    }

    extension Copyable
    {
    func copy() -> Self
    {
    return Self.init(other: self)
    }
    }


    class TestClass : Copyable
    {
    var name: String?

    var age: Int?

    init() {}

    required convenience init(other: TestClass)
    {
    self.init()

    self.name = other.name

    self.age = other.age
    }
    }

    ... tu auras une erreur : Method 'copy()' in non-final class 'TestClass' must return `Self` to conform to protocol 'Copyable'. Du coup, tu devrais soit marquer la classe comme final soit ajouter la méthode suivante dans la classe :



    func copy() -> Self
    {
    return type(of: self).init(other: self)
    }

    Mais, pour la struct, c'est plus facile :



    struct TestStruct : Copyable
    {
    var name: String?

    var age: Int?

    init() {}

    init(other: TestStruct)
    {
    self.name = other.name

    self.age = other.age
    }
    }

  • ... tu auras une erreur : Method 'copy()' in non-final class 'TestClass' must return `Self` to conform to protocol 'Copyable'. Du coup, tu devrais soit marquer la classe comme final soit ajouter la méthode suivante dans la classe :

    func copy() -> Self
    {
    return type(of: self).init(other: self)
    }



     


    Si tu ajoutes le code ci-dessus dans une extension prévue pour les classes, ça passe ? Sinon en jouant sur les allias ça peut passer ?


     


    L'idée est de ne pas avoir à  dupliquer le code dans toutes les classes... ::)

  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #6


    Si tu ajoutes le code ci-dessus dans une extension prévue pour les classes, ça passe ? Sinon en jouant sur les allias ça peut passer ?


     


    L'idée est de ne pas avoir à  dupliquer le code dans toutes les classes... ::)




     


    Non, le code dans la méthode ne change rien. C'est la signature de la méthode qui renvoie Self qui est le problème.


     


    C'est parce que, si tu ne marques pas la classe comme final, le compilateur ne peut pas déterminer le type de Self parce que il serait possible d'hériter de la classe ; ce qui changerais le type renvoyé.


     


    Côté Copyable, il sera toujours le cas que tu doives écrire le "copy constructor" pour chaque classe parce que les données qu'il faut copier seront différents.


     


    Si tu n'as pas d'hiérarchie de classes, c'est plus facile de les marquer comme final est le code dans l'extension ira pour toutes les classes.


  • Mais si tu crées un allias que tu le définis dans ta classe (implémentation du protocol) il saura forcément de quel type on parle, non ?


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #8

    Je ne comprend pas ce que tu dis. Tu peux montrer du code ?


     


    En même temps, peut-être j'ai réussi d'éviter le problème avec les classes non-final. C'était qqch comme ci que tu pensais ?



    protocol Copyable
    {
    associatedtype CopyableType

    init(other: Self)

    func copy() -> CopyableType
    }

    extension Copyable
    {
    func copy() -> Self
    {
    return Self.init(other: self)
    }
    }

  • Oui je pensais à  ça ou un truc du genre :



    protocol Copyable {
    init(other: Self)
    func copy() -> Self
    }

    extension Copyable: Any {
    func copy() -> Self {
    return self
    }
    }

    extension Copyable: AnyObject {
    func <T:Copyable>copy() -> T {
    return Self.init(other: self)
    }
    }
  • Joanna CarterJoanna Carter Membre, Modérateur


     


    Oui je pensais à  ça ou un truc du genre :



    protocol Copyable {
    init(other: Self)
    func copy() -> Self
    }

    extension Copyable: Any {
    func copy() -> Self {
    return self
    }
    }

    extension Copyable: AnyObject {
    func <T:Copyable>copy() -> T {
    return Self.init(other: self)
    }
    }



     


    Mais, comme je t'ai déjà  dit :



    extension Copyable: Any
    {
    func copy() -> Self
    {
    return self
    }
    }

    ... ne crée pas une copie.

  • JérémyJérémy Membre
    février 2017 modifié #11


    ... ne crée pas une copie.




     


    Oui oui oui mais dans la plupart des cas (vu qu'une structure n'est pas mutable) le code ci-dessous suffit. Sinon effectivement, il est nécessaire de créer une instance à  partir du constructeur par défaut.


     


    Pour toi, le code ci-dessous fonctionne pour les classes (sans redéfinition dans la classe) ?



    extension Copyable: AnyObject {
    func <T:Copyable>copy() -> T {
    return Self.init(other: self)
    }
    }

  • Joanna CarterJoanna Carter Membre, Modérateur

    Ce que j'ai fait avec le associatedtype est le seul moyen que j'ai encore trouvé qui réussit.



    protocol Copyable
    {
    init(other: Self)

    func copy() -> Self
    }

    extension Copyable where Self : Any
    {
    func copy() -> Self // Method 'copy()' in non-final class 'TestClass' must return `Self` to conform to protocol 'Copyable'
    {
    return self
    }
    }

    extension Copyable where Self : AnyObject
    {
    func copy<T : Copyable>() -> T
    {
    return Self.init(other: self) as! T
    }
    }


    class TestClass : Copyable
    {
    init(other: TestClass)
    {

    }
    }

    ça arrive parce que Any est valable comme type de base pour les classes, comme pour tous les types.


     


    Mais, si je fais ce :



    protocol Copyable
    {
    init(other: Self)

    func copy() -> Self
    }

    //extension Copyable : Any
    //{
    // func copy() -> Self
    // {
    // return self
    // }
    //}

    extension Copyable where Self : AnyObject
    {
    func copy<T : Copyable>() -> T // Method 'copy()' in non-final class 'TestClass' must return `Self` to conform to protocol 'Copyable'
    {
    return Self.init(other: self) as! T
    }
    }


    class TestClass : Copyable
    {
    required init(other: TestClass)
    {

    }
    }

    ... car la classe n'est pas encore marqué comme final


  • Joanna CarterJoanna Carter Membre, Modérateur

    Mais, si tu n'insistais pas à  différencier le comportement de faire une copie entre les classes et les structs, le code suivant serait plus simple et va bien :



    protocol Copyable
    {
    init(other: Self)

    func copy() -> Self
    }

    extension Copyable
    {
    func copy() -> Self
    {
    return Self.init(other: self)
    }
    }

    final class TestClass : Copyable
    {
    var name: String?

    init() { }

    required init(other: TestClass)
    {
    self.name = other.name

    print("class")
    }
    }


    struct TestStruct : Copyable
    {
    var name: String?

    init() { }

    init(other: TestStruct)
    {
    self.name = other.name

    print("struct")
    }
    }

    ... mais à  condition que tu marques les classes comme final. Sinon, il faut déclarer le associatedtype dans le protocol


  • C'est complètement débile que l'extension ne prenne pas en compte le type courant de l'objet... >:(


  • Plus simple et qui doit fonctionner pour les classes et structures (pas encore tester) mais on perd le typage :



    protocol Copyable {
    init(_ : Self)

    func copy() -> Any
    }

    extension Copyable {
    func copy() -> Any {
    return init(self)
    }
    }
  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #16


    Plus simple et qui doit fonctionner pour les classes et structures (pas encore tester) mais on perd le typage :



    protocol Copyable
    {
    init(_ : Self)

    func copy() -> Any
    }

    extension Copyable
    {
    func copy() -> Any
    {
    return init(self)
    }
    }



    Mais ça vol contre l'esprit de Swift. Le typage, c'est surtout ::)




  • Mais ça vol contre l'esprit de Swift. Le tapage, c'est surtout  ::)




     


    En même temps Apple ne se gêne pas d'en faire de même avec son protocol NSCopying... Puis vu qu'il n'existe pas de solution duper élégante sans faire du bricolage dans l'implémentation.


     


    Je reviens sur ça :


     




    Mais si tu veux utiliser ce code dans une struct :



    func copy() -> Self
    {
    return self
    }

    ... il ne revoie que la même référence. Ce n'est que sur la modification d'une struct que la référence change.


     




     


     


    Effectivement ce n'est pas une copie au sens strict du terme mais le comportement reste identique à  une vraie copie. La preuve :



    public protocol Copyable {
    init(_: Self)

    func copy() -> Any
    }

    public extension Copyable {
    public func copy() -> Any {
    return self
    }
    }

    struct MyStruct: Copyable {
    var x: Int

    init(x: Int) {
    self.x = x
    }

    init(_ object: MyStruct) {
    self.x = object.x
    }

    mutating func add(x: Int) {
    self.x += x
    }
    }

    var myStruct1 = MyStruct(x: 1)
    print(myStruct1.x) // 1
    myStruct1.add(x: 2)
    print(myStruct1.x) // 3
    var myStruct2 = myStruct1.copy() as! MyStruct // identique à  var myStruct2 = myStruct1
    myStruct1.add(x: 2)
    myStruct2.add(x: 9)
    print(myStruct1.x) // 5
    print(myStruct2.x) // 12

    Donc si on peut se passer d'un traitement c'est tout aussi bien. 

  • En définitive, voici ce que j'ai fait (merci à  Magiic pour le tuyau) :



    public protocol Copyable {
    init(_: Self)

    func copy() -> Any
    }

    public extension Copyable where Self: AnyObject {
    public func copy() -> AnyObject {
    return Self.(self)
    }
    }

    public extension Copyable where Self: Any {
    public func copy() -> Any {
    return self
    }
    }
  • Joanna CarterJoanna Carter Membre, Modérateur

    Est-ce que tu as essayé de compiler ton code ?


     


    Même après correction, tu devrais essayer d'implementer le protocol avec une class et une struct ;



    public protocol Copyable
    {
    init(_: Self)

    func copy() -> Any
    }

    public extension Copyable where Self: AnyObject
    {
    public func copy() -> AnyObject
    {
    return Self(self)
    }
    }

    public extension Copyable where Self: Any
    {
    public func copy() -> Any
    {
    return self
    }
    }

    class TestClass : Copyable
    {
    public required init(_: TestClass)
    {
    // ...
    }
    }

    struct TestStruct : Copyable // error : type TestStruct does not conform to protocol 'Copyable'
    {

    }

    Et, en supplement, l'erreur propose la solution : Protocol requires initializer 'init' with type 'Self'; do you want to add a stub?


     


    Même si tu ne veux pas utiliser le 'copy constructor' pour la struct, il le faut dans la struct pour que la struct conforme au protocole

  • Joanna CarterJoanna Carter Membre, Modérateur

    Parce que j'e suis au bon coe“ur, voici une solution (définitive ?)



    protocol Initialisable
    {
    init(_: Self)
    }

    protocol Copyable
    {
    func copy() -> Any
    }

    extension Copyable where Self: AnyObject & Initialisable
    {
    func copy() -> AnyObject
    {
    return Self(self)
    }
    }

    extension Copyable where Self: Any
    {
    func copy() -> Any
    {
    return self
    }
    }

    class TestClass : Copyable, Initialisable
    {
    public required init(_: TestClass)
    {

    }
    }

    struct TestStruct : Copyable
    {

    }
  • JérémyJérémy Membre
    février 2017 modifié #21

    Il y a une dans le code que je t'ai filé (je l'ai fait de mémoire à  la machine à  café xd ) :



    public protocol Copyable {
    init(_: Self)

    func copy() -> Any
    }

    public extension Copyable where Self: AnyObject {
    public func copy() -> Any {
    return Self.(self)
    }
    }

    public extension Copyable where Self: Any {
    public func copy() -> Any {
    return self
    }
    }

    Sinon oui, j'ai essayé hier dans playground. J'ai créé une classe et une structure, j'ai fait joujou avec et je n'ai pas constaté de soucis. Je t'ai mis un résultat partiel plus haut (que je vais te remettre ici).



    var myStruct1 = MyStruct(x: 1)
    print(myStruct1.x) // 1
    myStruct1.add(x: 2)
    print(myStruct1.x) // 3
    var myStruct2 = myStruct1.copy() as! MyStruct
    myStruct1.add(x: 2)
    myStruct2.add(x: 9)
    print(myStruct1.x) // 5
    print(myStruct2.x) // 12

  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #22

    Et, pour avoir le typage :



    protocol CopyInitialisable : AnyObject
    {
    init(_: Self)
    }


    protocol Copyable
    {
    associatedtype CopyableType

    func copy() -> CopyableType
    }


    extension Copyable where Self: CopyInitialisable
    {
    func copy() -> Self
    {
    return Self.init(_: self)
    }
    }


    extension Copyable where Self: Any
    {
    func copy() -> Self
    {
    return self
    }
    }


    class TestClass : Copyable, CopyInitialisable
    {
    var name: String?

    var age: Int?

    init() {}

    required convenience init(_ other: TestClass)
    {
    self.init()

    self.name = other.name

    self.age = other.age
    }
    }


    struct TestStruct : Copyable
    {
    var name: String?

    var age: Int?
    }

  • Moi j'aurais plus fait comme ça (même si ta solution est pertinente et intelligente ) :



    protocol Initialisable {
    init(_: Self)
    }

    protocol Copyable: Initialisable {
    func copy() -> Any
    }

    extension Copyable where Self: AnyObject {
    func copy() -> Any {
    return Self(self)
    }
    }

    extension Copyable where Self: Any {
    func copy() -> Any {
    return self
    }
    }

    Du coup dans tes implémentations :



    class TestClass : Copyable, Initialisable {
    public required init(_: TestClass) {

    }
    }

    Alors effectivement, tu vas devoir ajouter dans les structures init(_: TestClass) pour rien. Mais je préfère grandement un protocol qui fonctionne pour les classes et structures plutôt un contrat dépouillé de tout où l'implémentation doit s'adapter à  ses propres spécificités. C'est deux visions des choses qui peuvent s'opposer mais qui se défendent.


  • Joanna CarterJoanna Carter Membre, Modérateur


    Moi j'aurais plus fait comme ça (même si ta solution est pertinente et intelligente ) :



    protocol Initialisable {
    init(_: Self)
    }

    protocol Copyable: Initialisable {
    func copy() -> Any
    }

    extension Copyable where Self: AnyObject {
    func copy() -> Any {
    return Self(self)
    }
    }

    extension Copyable where Self: Any {
    func copy() -> Any {
    return self
    }
    }

    Du coup dans tes implémentations :



    class TestClass : Copyable, Initialisable {
    public required init(_: TestClass) {

    }
    }

    Alors effectivement, tu vas devoir ajouter dans les structures init(_: TestClass) pour rien. Mais je préfère grandement un protocol qui fonctionne pour les classes et structures plutôt un contrat dépouillé de tout où l'implémentation doit s'adapter à  ses propres spécificités. C'est deux visions des choses qui peuvent s'opposer mais qui se défendent.




     


    Mais non. Il y a, ici, deux intérêts.


     


    1. Copyable


    2. Initialisable


     


    En disant que quelque chose est Copyable, on ne dit pas qu'il faut être Initialisable ; voir l'exemple d'une struct.


     


    Du coup, il faut séparer ces deux intérêts dans deux protocoles.


     


    Et, en plus, si tu regardes mon dernier message tu y verras la solution la plus complète.

  • JérémyJérémy Membre
    février 2017 modifié #25


    En disant que quelque chose est Copyable, on ne dit pas qu'il faut être Initialisable ; voir l'exemple d'une struct.




     


    Ah mais je suis entièrement d'accord avec toi. L'idée de les séparer est judicieuse dans la mesure où nous sommes sur deux éléments distinct. J'ai bien lu ta proposition, elle est cohérente.


     


    Pourquoi je dis que le protocol Copyable dépend du protocol Initialisable ? C'est simple, pour que le premier puisse fonctionner (tel que je l'ai conçu) il a besoin du second. Or ce n'est pas un concept complètement folklorique de créer une telle dépendance entre deux éléments distincts. Pour preuve, le protocol BinaryFloatingPoint dépend du protocol FloatingPoint qui lui même dépend de Comparable. Or si tu crées ton propres type de nombres décimaux, en suivant ta logique, tu devras écrire :



    struct MyDouble: BinaryFloatingPoint, FloatingPoint, Comparable .....

    Si tu souhaites rester dans une certaine norme sans te dire "j'ai besoin de quoi pour que mon type suive la même logique que les autres nombre décimaux", par le jeu de dépendance, le code suivant suffit :



    struct MyDouble: BinaryFloatingPoint

    Moi je vois le truc comme ça : "pour faire une copie, j'ai besoin de ça".


     


    Du coup par le même raisonnement, le code suivant suffira :



    struct element: Copyable

    L'idée est d'éviter de pisser du code qui peut être factorisé (et donc de limiter les bugs).


     


    Dis moi ce que tu en penses. :)


  • Joanna CarterJoanna Carter Membre, Modérateur

    Il y a les protocoles qui dépendent sur les autres, bien sûr. Mais, dans ce cas là , Tu avais déterminer que l'on puisse copier une struct sans besoin d'un initialiseur. Du coup, deux intérêts - deux protocoles  8--)


     


    La pointe quand il faut "mélanger" les deux, c'est sur l'extension pour AnyObject, pour que tous les classes qui implémentent Copyable puissent être CopyInitialisable aussi.


     


    Mais, tu notes que j'ai fait hériter CopyInitialisable de AnyObject car c'est évident que tous qui soient CopyInitialisable doivent AnyObject au même temps.


  • C'est super ce que tu fais Jérémy mais n'oublie pas YAGNI (plus court et imagé : YAGNI)  .


  • JérémyJérémy Membre
    février 2017 modifié #28

    J'aime beaucoup ta proposition et je la trouve élégante. Il y a rien à  redire.


     


    Ce qui m'embête c'est ça :


     





    class TestClass : Copyable, CopyInitialisable



     


    Redéclarer ce protocol dans la classe ne me plait pas des masses mais faute de mieux, ça reste la solution la plus propre. :)


     



    Mais, tu notes que j'ai fait hériter CopyInitialisable de AnyObject car c'est évident que tous qui soient CopyInitialisable doivent AnyObject au même temps.



     


    Oui j'étais passé à  côté de ce détail, je n'avais pas vu ton "edit". ::)


     




    C'est super ce que tu fais Jérémy mais n'oublie pas <a data-ipb="nomediaparse" data-cke-saved-href="https://en.wikipedia.org/wiki/You_aren"href="https://en.wikipedia.org/wiki/You_aren" t_gonna_need_it"="">YAGNI (plus court et imagé :  YAGNI)  .




     


    :D


     


    Le but c'est de pouvoir créer des algorithmes qui fonctionnent aussi bien avec des structures (que nous aurions passées en paramètre) que des classes. ;)


  • JérémyJérémy Membre
    février 2017 modifié #29

    Enfin il y a quand même un souci si j'oublie dans la classe TestClass d préciser qu'elle répond au protocol CopyInitialisable, ce ne sera pas la bonne méthode copy() qui sera appelé.



    protocol CopyInitialisable : AnyObject {
    init(_: Self)
    }

    protocol Copyable {
    associatedtype CopyableType
    func copy() -> CopyableType
    }

    extension Copyable where Self: CopyInitialisable {
    func copy() -> Self {
    return Self.init(_: self)
    }
    }

    extension Copyable where Self: Any {
    // Cette méthode sera appelée !!!
    func copy() -> Self {
    return self
    }
    }

    class TestClass : Copyable {
    var name: String?
    var age: Int?
    init() {}
    required convenience init(_ other: TestClass) {
    self.init()
    self.name = other.name
    self.age = other.age
    }
    }

    1 - Le compilateur ne sera pas en mesure d'identifier le souci


    2 - La méthode appelée ne fera pas de copie mais retournera l'objet courant


     


    Mais bon... Tel est le quotidien des devs : Optimisation VS Maintenabilité


  • Joanna CarterJoanna Carter Membre, Modérateur
    février 2017 modifié #30


    Ce qui m'embête c'est ça :


     


     


    Redéclarer ce protocol dans la classe ne me plait pas des masses mais faute de mieux, ça reste la solution la plus propre. :)




     


    Je ne redéclare pas le protocol dans la classe, je dit à  la classe qu'elle doit conformer à  ce protocol.


     




    Le but c'est de pouvoir créer des algorithmes qui fonctionnent aussi bien avec des structures (que nous aurions passées en paramètre) que des classes. 




     


    Là , tu pourrais trouver des soucis ; plus que tu puisse imaginer à  ce moment  ???


     




    Enfin il y a quand même un souci si j'oublie dans la classe TestClass d préciser qu'elle répond au protocol CopyInitialisable, ce ne sera pas la bonne méthode copy() qui sera appelé.




     


    Mais bien sûr ! Si tu ne dit pas à  la classe qu'elle conforme au protocol qui déclare le version de copy(_: ), le compilateur passe, par défaut, à  la méthode la plus proche, qui est la méthode pour Self : Any, qui renvoie le même objet et pas la copie.


     


    Du coup, comme tu as trouvé, il faut suivre les conseilles de la petite nounours  8--)


     


    Tu peux applaudir maintenant  :D


  • JérémyJérémy Membre
    février 2017 modifié #31


    Je ne redéclare pas le protocol dans la classe, je dit à  la classe qu'elle doit conformer à  ce protocol.




     


    Je te présente mes excuses, c'est une erreur de vocabulaire de mon côté. o:)


     




    Là , tu pourrais trouver des soucis ; plus que tu puisse imaginer à  ce moment  ???




     


    Ah bon ? Tu peux m'en dire plus ? ???


     



    Mais bien sûr ! Si tu ne dit pas à  la classe qu'elle conforme au protocol qui déclare le version de copy(_: ), le compilateur passe, par défaut, à  la méthode la plus proche, qui est la méthode pour Self : Any, qui renvoie le même objet et pas la copie.



     


    Mais je n'ai jamais dit que ta solution était pourrit ! Bien au contraire. Je dis simplement que si le protocol Copyable dépendait de CopyInitialisable, on éviterait des oublies mais comme tu l'as mentionné, nous serions obligé de de créer la méthode init(_: Self) dans les structures qui en dépendent même si ça ne sert à  rien.  ::)


Connectez-vous ou Inscrivez-vous pour répondre.