97 votes

Comment tester l'égalité des fonctions et des fermetures ?

Le livre dit que "les fonctions et les fermetures sont des types de référence". Alors, comment savoir si les références sont égales ? == et === ne fonctionnent pas.

func a() { }
let å = a
let b = å === å // Could not find an overload for === that accepts the supplied arguments

85voto

drewag Points 12938

Chris Lattner a écrit sur les forums des développeurs :

Il s'agit d'une fonctionnalité que nous ne souhaitons pas prendre en charge. Il existe une variété de choses qui causeront l'égalité des pointeurs de fonctions (dans fonctions (au sens du système de types Swift, qui inclut plusieurs types de fermetures) échouera ou changera en fonction de l'optimisation. Si "===" était défini sur les fonctions fonctions, le compilateur n'aurait pas le droit de fusionner des corps de méthodes identiques, de partager des thunks et d'effectuer certaines optimisations de capture dans les fermetures. fermetures. De plus, l'égalité de ce type serait extrêmement surprenant dans certains contextes génériques, où l'on peut obtenir des thunks de réabstraction qui ajustent la signature réelle d'une fonction à celle que le type de fonction attend. type de fonction attend.

https://devforums.apple.com/message/1035180#1035180

Cela signifie que vous ne devriez même pas essayer de comparer les fermetures pour l'égalité car les optimisations peuvent affecter le résultat.

10voto

matt Points 60113

La méthode la plus simple consiste à désigner le type de bloc comme suit @objc_block et vous pouvez maintenant le convertir en un AnyObject qui est comparable à === . Exemple :

    typealias Ftype = @objc_block (s:String) -> ()

    let f : Ftype = {
        ss in
        println(ss)
    }
    let ff : Ftype = {
        sss in
        println(sss)
    }
    let obj1 = unsafeBitCast(f, AnyObject.self)
    let obj2 = unsafeBitCast(ff, AnyObject.self)
    let obj3 = unsafeBitCast(f, AnyObject.self)

    println(obj1 === obj2) // false
    println(obj1 === obj3) // true

5voto

dankogai Points 564

J'ai cherché la réponse, moi aussi. Et je l'ai enfin trouvée.

Ce dont vous avez besoin est le pointeur de fonction réel et son contexte caché dans l'objet de fonction.

func peekFunc<A,R>(f:A->R)->(fp:Int, ctx:Int) {
    typealias IntInt = (Int, Int)
    let (hi, lo) = unsafeBitCast(f, IntInt.self)
    let offset = sizeof(Int) == 8 ? 16 : 12
    let ptr  = UnsafePointer<Int>(lo+offset)
    return (ptr.memory, ptr.successor().memory)
}
@infix func === <A,R>(lhs:A->R,rhs:A->R)->Bool {
    let (tl, tr) = (peekFunc(lhs), peekFunc(rhs))
    return tl.0 == tr.0 && tl.1 == tr.1
}

Et voici la démo :

// simple functions
func genericId<T>(t:T)->T { return t }
func incr(i:Int)->Int { return i + 1 }
var f:Int->Int = genericId
var g = f;      println("(f === g) == \(f === g)")
f = genericId;  println("(f === g) == \(f === g)")
f = g;          println("(f === g) == \(f === g)")
// closures
func mkcounter()->()->Int {
    var count = 0;
    return { count++ }
}
var c0 = mkcounter()
var c1 = mkcounter()
var c2 = c0
println("peekFunc(c0) == \(peekFunc(c0))")
println("peekFunc(c1) == \(peekFunc(c1))")
println("peekFunc(c2) == \(peekFunc(c2))")
println("(c0() == c1()) == \(c0() == c1())") // true : both are called once
println("(c0() == c2()) == \(c0() == c2())") // false: because c0() means c2()
println("(c0 === c1) == \(c0 === c1)")
println("(c0 === c2) == \(c0 === c2)")

Consultez les URL ci-dessous pour savoir pourquoi et comment cela fonctionne :

Comme vous le voyez, il est capable de vérifier l'identité uniquement (le 2e test donne des résultats). false ). Mais cela devrait suffire.

2voto

Jiaaro Points 14379

Cela fait deux jours et personne n'a apporté de solution. Je vais donc transformer mon commentaire en réponse :

Pour autant que je sache, vous ne pouvez pas vérifier l'égalité ou l'identité des fonctions (comme votre exemple) et des métaclasses (par exemple, MyClass.self ):

Mais - et ce n'est qu'une idée - je ne peux pas m'empêcher de remarquer que les where clause dans les génériques semble être capable de vérifier l'égalité des types. Vous pouvez donc peut-être en tirer parti, au moins pour vérifier l'identité ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X