[swift] Invoquer une méthode avec un receiver donné

laurrislaurris Membre
janvier 2016 modifié dans Objective-C, Swift, C, C++ #1

En swift, on peut référencer une méthode, c'est à  dire une fonction liée à  une classe ou struct particulière.



let set:Set = [1,2]
let fonction:(Set) -> Set = set.intersectSet

Ensuite, on n'a plus qu'à  invoquer cette méthode avec les arguments ad hoc:



let result = fonction.([2,3] as Set)  // -> {2}

Dans l'exemple précédent, j'ai référencé la méthode par le biais d'une instance. Quand on l'appelle, cette instance devient implicitement le receiver de la fonction. Ca parait logique.


 


Maintenant, il se trouve que l'on peut aussi référencer la méthode en passant par le type lui-même:



let methode: Set<Int> -> (Set) -> Set = Set.intersect

Sympa Swift. Juste un petit souci: comment invoquer cette méthode avec un receiver de mon choix ?


 


C'est l'équivalent de apply en javascript qu'il faudrait et je ne l'ai pas trouvé pour l'instant. Et d'ailleurs, si ce n'est pas possible, on peut se demander pourquoi on nous laisse référencer un objet dont on ne peut rien faire !


 

Réponses

  • Self-réponse:


     


    On peut faire ça:



    let left:Set = [1,2]
    let right:Set =[2,3]
    let methode: Set<Int> -> (Set) -> Set = Set.intersect
    methode(left)(right) // -> {2}

    Je viens de relire le chapitre sur les fonctions du manuel Swift 2.1 et n'ai rien vu à  ce sujet. Quelqu'un sait si cette façon d'appeler une méthode est documentée qque part ?


  • AliGatorAliGator Membre, Modérateur
    Oui ça s'appelle le currying et en l'occurrence sur ce cas particulier c'est appliqué à  toutes les méthodes d'instances, qui sont aussi vues par Swift comme une méthode de classe prenant l'instance en paramètre et retournant la méthode d'instance associée.


    (C'est aussi dû au fait que Swift est un langage fonctionnel donc dans lequel les fonctions sont des first-class-citizen comme on dit, et peuvent être stockés dans des variables et passés en argument etc.)


    Tu trouveras d'avantages d'exemples pratiques sur mon blog dans l'article Fun with Functions.
  • FKDEVFKDEV Membre
    janvier 2016 modifié #4
    A priori, cela ne fonctionne pas les protocol, c'est dommage.
    (Enfin là  j'ai testé avec la sandbox IBM sous linux)
     

    protocol Bindable {
    func getValue()->Int
    }

    class TheClass : Bindable
    {
    func getValue()->Int { return 42}
    }

    let getValueMethod = Bindable.getValue <-- erreur
    var theObject:TheClass = TheClass()
    print(getValueMethod(theObject)())

  • Joanna CarterJoanna Carter Membre, Modérateur
    Les protocoles ne comportent pas le code exécutable, seulement les "signatures" ou déclarations des méthodes. Le comportement peut varier selon la classe qui implément le protocole.
  • Cela pourrait marcher quand même, non ?
    Il faudrait juste que le pointeur de fonction soit résolu au moment de l'appel car à  ce moment là  on connait le type de l'objet.
    Enfin bon, j'imagine qu'ils ont dû y penser... et que ce n'est pas possible pour une bonne raison, c'est quand même décevant.

    Et cela ferait une vraie différence par rapport aux vieux pointeurs de fonctions en C ou C++.

    Si je ne me mélange pas les pinceaux, je pense que cela pourrait permettre de faire du binding sans avoir à  forcer à  l'avance les protocoles à  utiliser.

    Pour un binding qui consomme un int, il faut une variable qui contient une fonction qui renvoie un int et une variable qui contient un objet qui à  priori implémente cette fonction.

    En fait ça reviendrait à  avoir un type de variable "fonction d'un protocole" qu'on pourrait utiliser sur un objet qui implémente le même protocole, sans avoir à  connaà®tre à  l'avance le protocole.


  • Les protocoles ne comportent pas le code exécutable, seulement les "signatures" ou déclarations des méthodes. Le comportement peut varier selon la classe qui implément le protocole.




     


    Le plus grosse fonctionnalité avancé en Swift 2 est le contraire de ce que tu dis :). C'est une révolution les "protocol extension" dans Swift. On peut implanter des méthodes dans un protocol et permettre aux autres classes/structs qui se conforme a ce protocol d'avoir ce comportement gratuitement. la library standard Swift se base beaucoup sur ça : CollectionType, SequenceType,....

  • Joanna CarterJoanna Carter Membre, Modérateur


    Le plus grosse fonctionnalité avancé en Swift 2 est le contraire de ce que tu dis :). C'est une révolution les "protocol extension" dans Swift. On peut implanter des méthodes dans un protocol et permettre aux autres classes/structs qui se conforme a ce protocol d'avoir ce comportement gratuitement. la library standard Swift se base beaucoup sur ça : CollectionType, SequenceType,....




     


    Problème :



    protocol Test
    {

    }

    extension Test
    {
    static func doIt(num: Int) -> Void
    {

    }
    }


    let f: (num: Int) -> Void = Test.doIt // error
    // Status member 'doIt' cannot be used on instance of type 'Test.Protocol'

    Comme j'ai dit, c'est pas possible, il faut un struct ou classe qui implement le protocole pour accéder les membres du protocol.

  • FKDEVFKDEV Membre
    janvier 2016 modifié #9

    Dans Xcode, cela fait planter le service playground, j'ai donc soumis un radar.


    Je n'ai pas encore essayé dans le REPL  Swift.


     




    A priori, cela ne fonctionne pas les protocol, c'est dommage.

    (Enfin là  j'ai testé avec la sandbox IBM sous linux)

     




    protocol Bindable {
    func getValue()->Int
    }

    class TheClass : Bindable
    {
    func getValue()->Int { return 42}
    }

    let getValueMethod = Bindable.getValue
    var theObject:TheClass = TheClass()
    print(getValueMethod(theObject)())



  • @AliGator


    J'ai lu ton blog, qui est très instructif. Tu dis que tu prépare un article sur les Abstract Class (ou similaire) en swift. J'en salive d'avance parce que je suis en train de porter NSExpression en swift. C'est un cas intéressant parce qu'il y a plusieurs contraintes, et pas seulement le fait que init ne retourne rien en swift, qui rendent la chose assez sportive.


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