2010-01-30 24 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... 

Respuesta

26

Para ampliar la respuesta de Laurent.

Un bloque es una combinación de implementación y datos. Para que dos bloques sean iguales, necesitarían tener la misma implementación exacta y haber capturado exactamente los mismos datos. La comparación, por lo tanto, requiere comparar tanto la implementación como los datos.

Uno podría pensar que comparar la implementación sería fácil. En realidad, no se debe a la forma en que funciona el optimizador del compilador.

Si bien la comparación de datos simples es bastante sencilla, los bloques pueden capturar objetos, incluidos los objetos C++ (que en realidad podrían funcionar algún día), y la comparación puede o no necesitar tener eso en cuenta. Una implementación ingenua simplemente haría una comparación de nivel de bytes de los contenidos capturados. Sin embargo, también se podría desear probar la igualdad de objetos utilizando los comparadores de nivel de objeto.

Luego está la cuestión de las variables __block. Un bloque, en sí mismo, no tiene ningún metadato relacionado con las variables capturadas __block porque no lo necesita para cumplir con los requisitos de dichas variables. Por lo tanto, la comparación no pudo comparar los valores de bloque __ sin cambiar significativamente el código del compilador.

Todo esto es para decir que, no, actualmente no es posible comparar bloques y describir algunas de las razones. Si cree que esto podría ser útil, presente un error a través del http://bugreport.apple.com/ y proporcione un caso de uso.

+0

Olvidé totalmente tomar constantes importadas y __bloquear objetos en cuenta.Demasiadas dependencias ¡Muchas gracias! Ahora está claro para mí. Llegué a la idea de comparar bloques porque quería determinar si el código de usuario establecía controladores de finalización similares a diferentes invocaciones de uno de mis métodos de objetos. Necesito pensar en una alternativa. –

4

No creo que esto sea posible. Los bloques se pueden ver aproximadamente como funciones avanzadas (con acceso a variables globales o locales). De la misma manera que no puede comparar el contenido de las funciones, no puede comparar el contenido de los bloques.

Todo lo que puedes hacer es comparar sus low-level implementation, pero dudo que el compilador garantice que dos bloques con el mismo contenido compartan su implementación.

+1

No es posible. – bbum

12

Poniendo a un lado los problemas de la implementación del compilador y el diseño del lenguaje, lo que está pidiendo es demostrablemente indecidible (a menos que solo se preocupe por detectar programas 100% idénticos). Decidir si dos programas calculan la misma función es equivalente a resolver el problema de detención. Esta es una consecuencia clásica del Teorema de Rice: cualquier propiedad "interesante" de las máquinas de Turing es indecidible, donde "interesante" significa que es cierto para algunas máquinas y falso para otras.

Simplemente por diversión, aquí está la prueba. Supongamos que puede crear una función para decidir si dos bloques son equivalentes, llamado EQ (b1, b2). Ahora usaremos esa función para resolver el problema de detención. Creamos un nuevo apeadero de función (H, I) que nos dice si máquina de Turing M se detiene ante la entrada que me gusta:

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

Si M (I) se detiene entonces los bloques son equivalentes, por lo HALT (M, I) devuelve SÍ. Si M (I) no se detiene, entonces los bloques son no equivalentes a, entonces HALT (M, I) devuelve NO. Tenga en cuenta que no tenemos que ejecutar los bloques - nuestra función EQ hipotética puede calcular su equivalencia con sólo mirarlos.

Hemos resuelto el problema de detención, que sabemos que no es posible. Por lo tanto, EQ no puede existir.