[swift] Le type de n'importe quelle fonction

J'ai besoin de grouper des fonctions acceptant différents types d'arguments et retournant également des types différents.


 


Problème, il n'existe pas de type ou de protocole qui correspond à  "une fonction en général".


 


Certes, on peut définir un type fonction dont les arguments et le return type se conforment à  un protocole commun, par exemple AnyObject.



let function:(AnyObject) -> AnyObject

Si j'essaie d'affecter une fonction existante à  la variable function, le compiler accepte une fonction de type



(AnyObject) -> NSNumber

, mais pas 



(NSNumber) -> AnyObject

En gros, il ne veut bien caster le return type mais pas l'argument.


 


Pourquoi ? Est-ce une limitation (peut-être provisoire) du type checker ou y a-t'il une raison plus fondamentale à  cela. Comment workarounder la chose ?


 


Xcode 7.2 swift 2.1


Mots clés:

Réponses

  • C'est un peu logique...


    Si tu prends ces 2 fonctions :



    func dummy(obj: AnyObject) { print("AnyObject") }
    func dummy(obj: String) { print("AnyObject") }

    Elles ont le même nom. Maintenant si le compilo ne s'emmêle pas les pinceaux c'est parce qu'elles n'ont pas la meÌ‚me signature. C'est le type d'argument qui est ici décisif dans le choix de la façon à  appeler. Un table est constituée à  la compilation et si on change la signature d'une méthode on risque vite de la perdre à  jamais.


     


    C'est aussi pour ça que :



    let f = dummy

    Fera une belle erreur :



    error: ambiguous use of 'dummy'

    Le return type n'aide pas non plus cela dit :



    func dummy(obj: AnyObject) -> Int { return 42 }
    func dummy(obj: AnyObject) -> Double { return 42.0 }

    dummy(NSNumber(integer: 0))

    Mènera exactement au meÌ‚me message d'erreur.


     


    À la rigueur tu peux utiliser la généricité :



    func dummy<T, U>(t: T, u: U) -> U {
    return u
    }
    dummy(42, u: 42.0)

    dummy renverra un Double mais juste parce qu'on lui a dit de le faire, sans plus.


     


    Bref je ne sais pas ce que tu essaie de faire mais ça ne semble pas être une bonne idée...


     


    PS: tu ne peux pas déclarer un type de fonction générique. Juste déclarer des fonctions génériques comme le code plus haut.



    var function: <T>(T) -> T

    n'a aucune chance d'exister.

  • laurrislaurris Membre
    janvier 2016 modifié #3

    Merci Pyroh pour ta réponse.


     


    Ce que j'essaie de faire, c'est simplement d'appeler une fonction à  partir d'un nom:String de fonction. Je sais, ce n'est pas très typé, pas très swift-like, mais c'est comme ça. La correspondance se fait avec un dictionnaire  de type <String,FunctionType> et c'est pour cela que je voudrais que toutes mes fonctions soient de type FunctionType.


     


    Dans ton exemple, tu prends le cas de deux fonctions avec le même nom mais des arguments de type différents. D'accord, je comprends que ce soit ambigu. Mais supposons qu'il n'existe dans le code compilé qu'une seule fonction dont l'argument puisse être upcasté vers un autre type.



    import Foundation
    func dummy(obj:NSNumber) -> NSNumber { return 1 as NSNumber }

    Qu'est-ce qui empêche de convertir dummy quand on fait: (ce qui donne une erreur)



    let f: (AnyObject) -> NSNumber = dummy

    Je ne vois pas d'ambiguà¯té là -dedans. NSNumber est bien un sous-type de AnyObject et il n'existe pas d'autre fonction du même nom dont l'argument est un sous-type de AnyObject.


     


    D'autant que le return type peut lui, être upcasté:



    let f:(NSNumber) -> AnyObject = dummy

    Pas d'erreur.


     


    Il existe peut-être d'autres contraintes propres au compiler et que j'ignore, mais je trouve dommage que mon exemple ne marche pas.


  • J'avais lu un long texte sur l'upcasting et le downcasting de Swift (peut être des release notes) mais plus moyen de mettre la main dessus. Bref ce que tu essaie de faire est impossible.


     


    Sinon si tu veux pouvoir faire appel à  une fonction depuis un string utilise simplement KVC en faisant de tes classes des sous classes de NSObject. Tu vas pouvoir utiliser les selectors et performSelector.


     


    C'est pas très swift-friendly cela dit. ApreÌ€s si tu nous dit dans quel contexte tu as besoin de ça on peut (peut-être) t'aider à  ré-architecturer tout ça.


  • Le contexte c'est le port de NSExpression en swift sans runtime Objective-C.


     


    Le mieux est de montrer ce que j'ai écrit pour l'instant. La fonction en question se trouve ici: NSExpression(forFunction:arguments:)


     


    Comme on peut le voir en commentaire, les fonctions pré-définies ont 4 ou 5 signatures différentes. Je crois que je vais finir par créer une collection par signature et rechercher dans chaque collection l'une après l'autre à  partir du nom de fonction.


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