2010-01-30 11 views
17
float pi = 3.14; 
float (^piSquare)(void) = ^(void){ return pi * pi; }; 
float (^piSquare2)(void) = ^(void){ return pi * pi; }; 

[piSquare isEqualTo: piSquare2]; // -> want it to behave like -isEqualToString... 

risposta

26

Per ampliare la risposta di Laurent.

Un blocco è una combinazione di implementazione e dati. Perché due blocchi siano uguali, avrebbero bisogno di avere la stessa identica implementazione e hanno catturato gli stessi identici dati. Il confronto, quindi, richiede il confronto tra l'implementazione e i dati.

Si potrebbe pensare che confrontare l'implementazione sarebbe facile. In realtà non dipende dal modo in cui funziona l'ottimizzatore del compilatore.

Mentre confrontare i dati semplici è abbastanza semplice, i blocchi possono catturare oggetti, inclusi oggetti C++ (che potrebbero effettivamente funzionare un giorno), e il confronto può o non può aver bisogno di tenerne conto. Un'implementazione ingenua farebbe semplicemente un confronto a livello di byte dei contenuti catturati. Tuttavia, si potrebbe anche desiderare di testare l'uguaglianza degli oggetti usando i comparatori a livello di oggetto.

Quindi c'è il problema delle variabili __block. Un blocco, di per sé, non ha in realtà alcun metadata relativo alle variabili catturate __block in quanto non ne ha bisogno per soddisfare i requisiti di dette variabili. Pertanto, il confronto non ha potuto confrontare i valori __block senza modificare in modo significativo il codegen del compilatore.

Tutto questo per dire che, no, non è attualmente possibile confrontare i blocchi e di delineare alcuni dei motivi. Se ritieni che ciò sia utile, invia un bug tramite http://bugreport.apple.com/ e fornisci un caso d'uso.

+0

Ho completamente dimenticato di prendere in considerazione costanti importate e oggetti __block.Troppe dipendenze. Grazie mille! Ora è chiaro per me. Mi è venuta l'idea di confrontare i blocchi perché volevo determinare se il codice utente impostava simili gestori di completamento a invocazioni diverse di uno dei miei metodi oggetti. Hai bisogno di pensare ad un'alternativa. –

4

Non credo sia possibile. I blocchi possono essere approssimativamente visti come funzioni avanzate (con accesso a variabili globali o locali). Allo stesso modo in cui non puoi confrontare il contenuto delle funzioni, non puoi confrontare il contenuto dei blocchi.

Tutto quello che puoi fare è confrontare il loro low-level implementation, ma dubito che il compilatore garantisca che due blocchi con lo stesso contenuto condividano la loro implementazione.

+1

Non è possibile. – bbum

12

Mettendo da parte le questioni di attuazione compilatore e progettazione del linguaggio, quello che stai chiedendo è dimostrabilmente indecidibile (a meno che non vi interessa soltanto rilevare il 100% dei programmi identici). Decidere se due programmi calcolano la stessa funzione equivale a risolvere il problema dell'arresto. Questa è una conseguenza classica del Teorema di Rice: Qualsiasi proprietà "interessante" delle macchine di Turing è indecidibile, dove "interessante" significa semplicemente che è vero per alcune macchine e falso per gli altri.

Solo per divertimento, ecco la prova. Supponiamo che possa creare una funzione per decidere se due blocchi sono equivalenti, chiamato EQ (b1, b2). Ora useremo questa funzione per risolvere il problema dell'arresto. Creiamo una nuova funzione HALT (M, I) che ci dice se macchina di Turing M si ferma su di ingresso mi piace così:

BOOL HALT(M,I) { 
    return EQ(
    ^(int) {return 0;}, 
    ^(int) {M(I); return 0;} 
); 
} 

Se M (I) si ferma quindi i blocchi sono equivalenti, in modo da HALT (M, I) restituisce SÌ. Se M (I) non si ferma, i blocchi sono non equivalenti a, quindi HALT (M, I) restituisce NO. Si noti che non abbiamo a eseguire i blocchi - la nostra funzione EQ ipotetica in grado di calcolare la loro equivalenza solo guardandoli.

Ora abbiamo risolto il problema di interruzione, che sappiamo non è possibile. Pertanto, l'EQ non può esistere.