Perché il compilatore non assume che la condizione dell'istruzione if sia corretta al suo interno?

2

Prima di tutto: scusa per il titolo, ma non ho ora come formulare meglio il significato della mia domanda successiva in una singola frase.

Mentre stavo scrivendo il seguente codice Swift :

if errorData.isMemberOfClass(UIAlertController) {
    self.presentViewController(errorData, animated: true, completion: nil)
} else {
    /* Some other code */
}

per il mio progetto personale il compilatore mi ha dato questo errore:

'AnyObject' is not convertible to 'UIAlertController'; did you mean to use 'as!' to force downcast?

e non mi lascerà più compilare il compilatore se non cambierò il mio codice in questo:

if errorData.isMemberOfClass(UIAlertController) {
    self.presentViewController(errorData as! UIAlertController, animated: true, completion: nil)
} else {
    /* Some other code */
}

Ma non capisco: se faccio in modo che il programma controlli la classe di errorData (che, per essere precisi, è di classe AnyObject ) usando if statement perché mi costringe a forzare il downcast contro il tipo di classe dovrebbe essere all'interno di if ? In altre parole: il compilatore non sa già che all'interno dell'istruzione errorData è UIAlertController ? Se invece il programma non è proseguito nella parte else, così errorData potrebbe anche essere di classe Int o String per esempio

    
posta Aluminum 05.07.2016 - 13:24
fonte

3 risposte

10

Sì, il compilatore potrebbe dedurre il fatto che la variabile è del tipo previsto, poiché è stata testata immediatamente prima. E infatti questa sarebbe la prossima cosa più semplice da aggiungere al codice per l'analisi del flusso di dati.

Tuttavia, il compilatore mai sarà in grado di dedurre quanto più possibile sul programma. Anche una tale (a voi) proprietà completamente ovvia come il tipo in questo costrutto deve essere programmato in esso esplicitamente. Indipendentemente da quanto sforzo gli autori del compilatore dedicano all'operazione, ci sarà sempre una condizione che sembra ovvia agli usi umani, ma non è affatto ovvia al compilatore. (Il problema è aggravato dal fatto che la percezione umana funziona in modo adattivo: rendere un compilatore più intelligente e gli utenti cominceranno ad aspettarsi cose più intelligenti da esso. Le detrazioni che l'anno scorso sembravano piuttosto avanzate sembreranno ora di routine e nuovi problemi sembreranno "il compilatore dovrebbe facilmente riconoscibile ".)

Pertanto, stai semplicemente osservando il limite corrente tra ciò che è teoricamente possibile e ciò che (secondo gli autori del compilatore) vale la pena fare. Non essere triste Tra un paio d'anni avranno aggiunto questa logica, e a quel punto troverai qualcos'altro irragionevole!

    
risposta data 05.07.2016 - 13:29
fonte
4

Ci sono diverse possibili risposte a questo.

La risposta numero 1 è che isMemberOfClass è un metodo come qualsiasi altro metodo. Il compilatore non ha assolutamente idea di cosa stia facendo questo metodo e di cosa significhi il codice. Potrebbe anche essere sovrascritto in una sottoclasse. Il metodo non è nemmeno parte di Swift, fa parte della libreria standard Objective-C.

La risposta numero 2 è che, beh, forse il compilatore fa lo sa, forse genera codice più efficiente a causa di ciò, ma la semantica linguistica di Swift dice che puoi solo chiamare metodi che esistono su il tipo statico del riferimento. Il compilatore non è autorizzato a violare la semantica della lingua. Può usare queste informazioni per vari scopi come l'ottimizzazione, generare messaggi di errore migliori, ecc., Ma potrebbe non usarlo per fare cose che le specifiche della lingua vietano.

La risposta numero 3 è che ci sono sono lingue che hanno un tipo case o tipo guard costrutto, e i cast di Kotlin sono già stati menzionati. Notate che nel caso di Kotlin if (errorData is UIAlertController) , il costrutto is è un costrutto basato su linguaggio per il test del tipo, quindi il compilatore conosce cosa significa, mentre isMemberOfClass è solo un metodo come qualsiasi altro metodo, non ha alcun significato speciale per il compilatore. Quindi, una funzionalità come questa potrebbe essere aggiunta a Swift, ma probabilmente usando un test di tipo incorporato nel linguaggio ( is ), non un metodo (simile a if let per gli optionals).

In realtà non conosco Swift, ma penso che tu possa fare qualcosa del genere:

if let errorData = errorData as? UIAlertController {
    self.presentViewController(errorData, animated: true, completion: nil)
} else {
    /* Some other code */
}

Puoi immaginare che ci siano alcuni modi per introdurre lo zucchero sintattico per accorciarlo, ma non di molto.

    
risposta data 09.07.2016 - 01:47
fonte
1

Una lingua deve essere ben definita. Sarebbe terribile se il codice fosse valido o meno a seconda dell'abilità del compilatore. Ciò porterebbe al codice eseguito su un compilatore e non su un altro.

Ricorda che Java aveva il requisito che ogni variabile debba essere definita prima di essere utilizzata. Ma quello non era in realtà il requisito, perché ciò avrebbe portato al problema di cui sopra. Quindi il requisito era che ogni variabile debba essere definita prima di essere utilizzata, in un modo riconoscibile da un algoritmo molto ben definito. Eri non autorizzato a scrivere un compilatore più intelligente che riconoscesse cose che altri compilatori non avevano.

Quindi i progettisti linguistici dovrebbero trovare le regole esattamente quando tali deduzioni possono e devono essere fatte, e questo è molto, molto difficile.

D'altra parte, il linguaggio ha un modo molto semplice per scrivere questo codice usando "if let".

    
risposta data 09.07.2016 - 13:40
fonte

Leggi altre domande sui tag