objective c - Técnicas para implementar-hash en objetos de cacao mutables
objective-c cocoa (5)
La pregunta aquí no es cómo cumplir con estos dos requisitos, sino con cuál debe cumplir. En la documentación de Apple, se establece claramente que:
un diccionario mutable puede colocarse en una tabla hash pero no debe cambiarlo mientras está allí.
Dicho esto, parece más importante que cumpla con el requisito de igualdad de los hashes. El hash de un objeto siempre debe ser una forma de verificar si un objeto es igual a otro. Si este no es el caso, no es una verdadera función hash.
Solo para finalizar mi respuesta, daré un ejemplo de una buena implementación de hash. Digamos que está escribiendo la implementación de -hash
en una colección que ha creado. Esta colección almacena una matriz de NSObjects como punteros. Dado que todos los objetos NSO implementan la función hash, puede usar sus valores hash para calcular el hash de la colección:
- (NSUInteger)hash {
NSUInteger theHash = 0;
for (NSObject * aPtr in self) { // fast enumeration
theHash ^= [aPtr hash];
}
return theHash;
}
De esta forma, dos objetos de colección que contienen los mismos punteros (en el mismo orden) tendrán el mismo hash.
La documentación de -hash
dice que no debe cambiar mientras se almacena un objeto mutable en una colección, y de manera similar la documentación para -isEqual:
dice que el valor -hash
debe ser el mismo para objetos iguales.
Teniendo esto en cuenta, ¿alguien tiene alguna sugerencia sobre la mejor manera de implementar -hash
tal que cumpla con ambas condiciones y, sin embargo, se calcule de manera inteligente (es decir, no solo devuelva 0
)? ¿Alguien sabe cómo hacen las versiones mutables de las clases proporcionadas por el framework?
Lo más simple es, por supuesto, olvidar la primera condición (que no cambia) y simplemente asegurarme de que nunca mute accidentalmente un objeto mientras está en una colección, pero me pregunto si hay alguna solución que sea más flexible.
EDITAR: Me pregunto si es posible mantener los 2 contratos (donde los objetos iguales tienen hashes iguales, y los hashes no cambian mientras el objeto está en una colección) cuando estoy mutando el estado interno del objeto. Mi inclinación es decir "no", a menos que haga algo estúpido como siempre devolver 0 para el hash, pero es por eso que estoy haciendo esta pregunta.
En Java, la mayoría de las clases mutables simplemente no anula Object.hashCode () para que la implementación predeterminada devuelva un valor que se basa en la dirección del objeto y no cambia. Puede ser lo mismo con Objective C.
Interesante pregunta, pero creo que lo que quieres es lógicamente imposible. Digamos que comienzas con 2 objetos, A y B. Ambos son diferentes y comienzan con diferentes códigos hash. Usted agrega ambos a alguna tabla hash. Ahora, quiere mutar A, pero no puede cambiar el código hash porque ya está en la tabla. Sin embargo, es posible cambiar A de tal manera que sea .equals () B.
En este caso, tiene 2 opciones, ninguna de las cuales funciona:
- Cambie el hashcode de A a B.hombre de código, lo que infringe la restricción de no cambiar los códigos hash en una tabla hash.
- No cambie el código hash, en cuyo caso A.equals (B) pero no tienen los mismos códigos hash.
Me parece que no hay forma posible de hacerlo sin usar una constante como un código hash.
Mi lectura de la documentación es que el valor de un objeto mutable para hash
puede (y probablemente debería) cambiar cuando está mutado, pero no debería cambiar cuando el objeto no ha sido mutado. La parte de la documentación a la que hacer referencia, por lo tanto, es: "No mutes los objetos que están almacenados en una colección, porque eso hará que cambie su valor hash
".
Para citar directamente de la documentación de NSObject para el hash
:
Si se agrega un objeto mutable a una colección que usa valores hash para determinar la posición del objeto en la colección, el valor devuelto por el método hash del objeto no debe cambiar mientras el objeto está en la colección. Por lo tanto, el método hash no debe basarse en ninguna información de estado interno del objeto o debe asegurarse de que la información de estado interno del objeto no cambie mientras el objeto está en la colección .
(Énfasis mío)
Dado que ya está anulando -isEqual: para hacer una comparación basada en el valor, ¿está seguro de que realmente necesita molestarse con -hash?
No puedo adivinar exactamente para qué necesita esto, por supuesto, pero si desea hacer una comparación basada en valores sin desviarse de la implementación esperada de -isEqual: para devolver SÍ solo cuando los valores hash son idénticos, un mejor enfoque podría ser imitar NSString''s -isEqualToString :, para crear su propio método -isEqualToFoo: en lugar de usar o anular -isEqual :.