2017-04-19 7 views
1

Est-ce que les instructions de basculement avec plusieurs évaluations sont en court-circuit?Est-ce que Swift Switch court-circuite?

Cela n'a probablement pas d'importance, mais je suis curieux.


Voici un exemple simple:

let one = 1 
let two = true 
let three = false 


switch (one, two, three) { 
case let (0, b, c) where b==c: 
    break 

case (0, true, true): 
    break 

default: 
    break 
} 

Dans la première déclaration de cas, sera le 'où' l'évaluation même se produire?

Dans le deuxième cas, le 'two' == true se produira-t-il?

Répondre

2

@ réponse J.beenie traite votre première question gentiment (et de manière convaincante). b == c ne sera pas appelé puisque votre one initial ne correspond pas à 0, un AND court-circuit classique.

Votre deuxième question dépend de l'implémentation de == pour les tuples. Selon a comment to this question cela fait partie de la langue Swift depuis 2.2.1 et l'implémentation standard serait bien sûr en court circuit car c'est la chose la plus rapide à faire. Donc, dans votre deuxième cas, le deuxième élément ne serait pas comparé.

Btw: Vous n'avez pas besoin de break dans une instruction Swift , au lieu de fallthrough si vous le souhaitez.

Correction: Ma proposition s'est révélée être seulement à moitié correcte. Pattern correspondant dans les déclarations switch semble faire plus que ce à quoi je m'attendais. J'ai essayé de pirater == en utilisant mon propre Bool ENUM (à peu près suivant this post (et ajustement pour Swift 3)) et a obtenu des résultats surprenants:

import Cocoa 

let one = 1 
let two:MyBool = .myTrue 
let three:MyBool = .myFalse 
typealias ThreeTuple = (o:Int, tw:MyBool, th:MyBool) 
let tuple:ThreeTuple 
tuple = (one, two, three) 

switch tuple { 
case let (1, b, c) where b == c: 
    print("first case")  
case (1, .myTrue, .myFalse): 
    print("second case") 
default: 
    print("default") 
} 

enum MyBool : ExpressibleByBooleanLiteral, Equatable { 
    case myTrue, myFalse 
    public init() { self = .myFalse } 
    public init(booleanLiteral value: BooleanLiteralType) { 
     self=value ? .myTrue : .myFalse 
    } 
} 

func ==(lhs: MyBool, rhs: MyBool) -> Bool { 
    print("evaluate ==") 
    switch (lhs, rhs) { 
    case (.myTrue,.myTrue), (.myFalse,.myFalse): 
     return true 
    default: 
     return false 
    } 
} 

qui donne

evaluate == 
second case 

à quel point j'étais majorly surpris. L'évaluation unique de == pour MyBool valeurs provient de la clause where b == c dans la première case et toutes les tuple « comparaisons » ne pas utiliser la fonction MyBool==du tout !!Je me doutais bien l'optimisateur interférait donc je me suis tourné le switch en func comme

func match(_ tuple:ThreeTuple) { 
    switch tuple { 
    case let (1, b, c) where b == c: 
     print("first case") 
    case (1, .myTrue, .myFalse): 
     print("second case") 
    default: 
     print("default") 
    } 
} 

qui devrait empêcher l'optimisation excessive au moment de la compilation, mais quand je demande maintenant

match((1, .myTrue, .myTrue)) 
match((1, .myTrue, .myFalse)) 
match((0, .myTrue, .myFalse)) 

je reçois

evaluate == 
first case 
evaluate == 
second case 
default 

où le evaluate == proviennent encore que de la première case. Donc, la seule conclusion raisonnable semble être qu'il y a "une autre magie" qui se passe pendant la correspondance de modèle dans les instructions switch. J'ai essayé de google si je pouvais comprendre ce que c'était, mais en vain jusqu'à présent. De toute façon, il semble y avoir plus de court-circuit que je ne l'aurais cru.

+0

Il est cool d'écrire du code pour prouver la deuxième déclaration de cas également des courts-circuits. Je n'arrive pas à comprendre comment le faire. –

+0

@ J.beenie vous avez raison, il semble y avoir quelque chose d'autre, la correspondance des motifs semble être * vraiment bien optimisé * (TM) dans Swift. Voyons s'il y a quelqu'un qui peut faire la lumière sur cela. – Patru

1

Testez votre question avec le code suivant:

let one = 1 
let two = true 
let three = false 


switch (one, two, three) { 
case let (0, b, c) where b - c: 
    break 

case (0, true, true): 
    break 

default: 
    break 
} 

extension Bool{ 
    static func - (lhs: Bool, rhs: Bool) -> Bool { 
     print("foo") 
     return lhs == rhs 

    } 
} 

dans une aire de jeux

changer juste le premier 0 à 1 et voir ce qui se passe.

La réponse est Oui;) elle court-circuite.