From generic protocol to type !
Jérémy
Membre
Bonjour à tous,
Je souhaiterais faire d'un protocol générique, un type à part entière. Plutôt que de rentrer dans de longues explications, voici un code que j'ai inventé pour illustrer ma question.
public protocol Generic {
associatedtype T
var x: Int { get set }
var fx: Double { get }
func gettingClass()-> T
}
// TataProtocol hérite de Generique pour être certain que toute implémentation de protocol
// répondra au contrat Generique (idem pour TitiProtocol)
public protocol TataProtocol: Generic {
func sayedHello()-> String
}
public protocol TitiProtocol: Generic {
func sayedGoodBye()-> String
}
public class Gen<Toto>: Generic {
public typealias T = Toto
private var _x: Int = 0
public var x: Int {
get {
return _x
}
set {
if newValue != _x {
_fx = nil
_x = newValue
}
}
}
private var _fx: Double?
public var fx: Double {
// On imagine ici un traitement lourd, pour des raisons d'optimisation on garde
// en mémoire le résultat du calcul
if _fx == nil {
_fx = cos(pow(Double(x) - 7.0, 3) * M_PI / 180.0)
}
return _fx!
}
public func gettingClass() -> Toto {
return Gen<Toto>() as! Toto
}
}
public class Tata: Gen<Tata>, TataProtocol {
public func sayedHello()-> String {
return "Hello Tata!"
}
}
public class MyTata: Gen<Tata>, TataProtocol {
public func sayedHello()-> String {
return "Hello MyTata!"
}
}
public class Titi: Gen<Titi>, TitiProtocol {
public func sayedGoodBye()-> String {
return "Bye Titi!!!"
}
}
let tata: Tata = Tata() // Ici pas de problème
tata.sayedHello()
tata.x = 19
print(tata.fx)
let y: TataProtocol = Tata() // Erreur : Protocol 'FirstProtocol' can only be
// used as a generic constraint because
// it has Self or associated type requirements
Auriez vous une petite idée ? ::)
Mots clés:
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Oui. Tout simplement, on ne peut pas faire comme ça ::)
À part d'un exercice, qu'est-ce que tu voudrais faire avec tels protocoles / classes ?
J'aimerais qu'un protocol B oblige à implémenter un protocol A. Pour éviter du code redondant, j'ai voulu passer par une classe générique... Pourquoi utiliser le protocol B comme typage ? Pour que toutes les implémentations de B puissent être utilisées.
ça j'avais cru comprendre puisque ça ne fonctionne pas. ::)
Tu me conseilles quoi ? De créer une extension de mon protocol A ("Generic" dans mon exemple) dans lequel je mettrai mon code commun ?
OK. Mais pourquoi l'associatedtype et qu'est-ce que tu comptes faire avec gettingClass() ?
Il faut expliquer plus de ce que tu veuilles faire
Je vais créer dans la soirée un exemple un peu plus parlant pour illustrer ma demande (qui relève plus de l'exercice que d'un réel cas que j'ai dans un projet).
Tu ne peux pas faire ta dernière exécution parce que ton protocol dispose d'un type générique que tu ne fournis pas à l'initialisation. Ce que tu essayes de faire n'est pas permis, du moins actuellement.
Tu peux le faire passer dans une fonction qui prend en générique ton protocol, c'est ce qu'ils expliquent.
Je viens de faire un autre petit exemple à Joanna qui sera (je l'espère) un peu plus parlant pour elle :
Mieux Joanna ?
En gros si je comprends bien, tu ne peux pas utiliser un protocol comme type de déclaration d'une variable du moment que ce dernier dispose d'un type générique ? ???
Je vois pas la valeur ajoutée d'une telle contrainte.
Il est tout de même mieux d'utiliser les protocol comme type pour déclarer des variables... ::)
Tu as beaucoup à apprendre :-*
Ce que tu as fait, c'est bien compliqué.
Pour le simplifier un peu :
Code de test
Et, j'oserais dire que l'on puisse oublier SquareProtocol et RectangleProtocol
Le melon qu'elle a celle la ! xd
J'avoue que ta solution est plus propre et fatalement moins complexe.
Oui... Mais non ! Pourquoi ?
Pour déclarer une variable (exemple, quand tu passes un paramètre dans une méthode), je préfère utiliser le protocol pour être certain que toutes ses implémentations puissent y être éligible.
Je trouve préférable d'utiliser :
Que :
Je propose l'explication suivante (merci de me contredire si je me trompe car je ne suis pas un pro de la compilation swift) :
Pour l'instant, on ne peut pas faire ça :
C'est à cause du côté très statique et typé de swift.
A chaque fois que tu vas créer une struct ou une class dérivant de Generic, il faut imaginer que swift va créer une nouvelle "instance" du protocol Generic en remplaçant T par le type utilisé.
Donc si tu fais un Generic avec T = String et un autre avec T = Int, tu vas te retrouver avec deux protocoles incompatibles puisque l'un a une fonction qui renvoie un String et l'autre la même fonction qui renvoie un Int.
Comment une struct pourrait dériver de ces deux protocoles à la fois ?
via http://stackoverflow.com/questions/27404137/swift-types-returning-constrained-generics-from-functions-and-methods
Cela pourrait surement fonctionner avec un langage vraiment dynamique pour qui Generic resterait un seul protocol paramétrable au moment du runtime.
Si si si, tu peux. En revanche, tu ne peux le définir comme un type à part entière (il en sera de même pour les protocols qui en hériteront) :
Oui et non. Les instances sont créées à partir de l'implémentation (struc ou class) et non du protocol. Le protocol a la foncion de définir un contrat. Faut voir le truc dans le sens "si tu signes avec moi (si tu veux m'inplémenter), tu dois pouvoir gérer ça ça et ça et faire ceci et cela". Ceci dit, je comprends l'idée de ta phrase.
Dans l'absolue, si tu n'utilises, pas dans ta façon de coder, les protocols comme typage, tu n'auras pas de soucis.
Mais c'est sur ce point précis que la bât blesse sur le langage (qui se dit orienté protocol)... Pourquoi ne pas pouvoir utiliser Generic comme type ? Le contrat est clair, "gettingClass()-> T = retourne moi la classe dont tu auras customisé le type". Du coup, que ce soit du Int ou de String on s'en fout complètement...
Et je suis d'accord sur ça. Du coup, et étant donné que Square n'est qu'un Rectangle avec width et height qui sont égaux, je propose encore un petit changement :
ça te plaà®t mieux ? ???
Non. ;D
Pourquoi un carré qui est un rectangle particulier n'a t'il pas son propre protocol ?
Exemple :
Oui, non, peut-être. Mais, avec ça, on aurait, apparemment, trois vars : height, width et side ; on pourrait conjecturer que c'est un objet en trois dimensions, non ?
8--)
Elle est difficile à satisfaire !
Contre proposition :
Ou :
Mais, avec ceux, on perde le GenericFormProtocol ::)
Bah non, si tu fais ça :
Bah ouais ! Mais ce n'était ce que tu as écrit :-*
Petite erreur d'adaptation... 8--)