martes, 10 de febrero de 2009

Igualdad de Objetos

En el post anterior hable sobre el hecho de identificar correctamente la identidad de un objeto y sobre el verdadero significado del mensaje #==, que en definitiva verifica si dos objetos son idénticos, puesto que dos objetos pueden no ser idénticos pero estar representando el mismo ente.
Como bien comenta Gabriel (Gaboto) en un comentario, puede suceder que existan dos objetos representando el mismo ente (su ejemplo me confundió un poco) y debemos tener alguna manera de identificar dicha situación. Un ejemplo claro se da en Smalltalk con la clase Date, donde dos instancias distintas (o sea no idénticas) pueden representar el mismo día (por ejemplo hoy). 
El mensaje que utilizamos para saber si dos objetos están representando el mismo ente es el mensaje #=, más conocido como "igual". Su semántica es devolver verdadero si dos objetos representa el mismo ente, lo que en lenguaje vulgar o natural decimos "si son iguales"... claro está, acá empieza la confusión. Son iguales por estar representando al mismo ente (por ejemplo el día de hoy, que es idéntico a si mismo) pero no son el mismo objeto necesariamente y por no lo tanto no idénticos entre sí.
Por lo tanto el mensaje #= toma una nueva dimensión y para mí es más claro decir que este mensaje "devuelve true si dos objetos representan el mismo ente", puesto que definir qué significa "si son iguales" es bastante problemático como veremos más adelante. Sería menos confuso usar otro mensaje para esta semántica, por ejemplo #representsSameEntityAs:, pero bueno, ya estamos muy acostumbrado al otro.
El motivo por el cual dos objetos pueden representar el mismo ente se debe únicamente a problemas computacionales. En el caso de la clase Date esto se podría solucionar teniendo una cache de fechas creadas y siempre devolver el mismo objeto para la misma fecha, una implementación similar a la de Symbol, sin embargo hacer esto puede no tener sentido por poder ocupar más memoria o ser más lento que la implementación actual al tener que buscar el objeto en esa cache. En definitiva, si existe un solo objeto para representar un ente o si existen varios es una decisión implementativa y es por ello que siempre hay que utilizar el mensaje #= para saber si dos objetos representan el mismo ente (si son iguales) y sólo utilizar el mensaje #== para dominios computaciones, donde realmente nos interese saber si estamos hablando del "mismo objeto", del objeto que ocupa la misma zona de memoria.
Ahora bien, si se decide que puede haber más de un objeto para representar el mismo ente como el caso de Date, hay que asegurar que esos objetos sean inmutables porque sino estaremos en graves problemas puesto que podrían existir representaciones desincronizadas del mismo ente (creo que a esto apuntaba Gaby con su ejemplo). Imagínense dos objetos representando la misma cuenta corriente donde el saldo en uno es distinto al saldo en otro y donde claramente solo uno de ellos representa bien el ente en ese momento por tener el mismo saldo de la cuenta (por supuesto que también podría suceder que ninguno represente el ente por tener los dos el saldo incorrecto...). En definitiva, un grave problema.
Si no es factible que dicho objeto sea inmutable, hay que asegurar que exista una única instancia "master" para representar el ente y el resto sean solo "representaciones temporales" que tendrán un propósito determinado y esporádico. Un ejemplo de este caso es lo que en mi presentación de Smalltalks mostré como "sincronización" de objetos que comentaré en más detalle más adelante, pero que básicamente consiste en sincronizar la copia "master" con la "termporal" de una vez, con el envío de un solo mensaje. Por supuesto que acá nos metemos con problemas transaccionales, pero por ahora también los esquivaré.
Otro tema interesante que se desprende de este es definir exactamente que significa "que sean iguales". Por ejemplo, 0.5 y 1/2 ¿son iguales?. Ambos representan la misma cantidad, la mitad de algo, por lo tanto desde el punto de vista numérico nos interesa que sean iguales, pero también son distintos. Por ejemplo, desde el punto de vista implementativo uno será representado como un número de punto flotante y el otro como fracción. Mismos ejemplos se pueden dar para medidas equivalentes representadas por distintas unidades. Más interesante aún es pensar si 0 es igual a 0 metro, 0 litro, 0 pesos, etc. No voy a ahondar mucho en este tema ahora, pero la verdad es que sí, todos estos objetos representan lo mismo, o sea nada en cantidad y por lo tanto "son iguales". A muchos esta afirmación les parecerá muy loca pero la explicación matemática es clara. Una medida es la representación de la multiplicación de un número por una unidad, por lo tanto 0 metro es lo mismo a decir 0*metro, que algebraicamente es 0 de la misma manera que es 0 la expresión algebraica 0*A. Algunos denominan esta situación como "el cero polimórfico". Ahora bien, todas estas medidas están midiendo cosas distintas y sería interesante poder determinar esa situación, ¿cómo lo hacemos si devuelven true cuando se les envía el mensaje #=? (lo mismo para 1 metro y 1000 milimetros o 100 centímetros, etc). En Mercap estuvimos discutiendo mucho sobre esta situación, discusión en la que también participó Máximo Prieto y que fueron muy interesantes y acalorados (por qué ocultarlo). Llegamos a la conclusión que como en matemática, debería existir la posibilidad de definir distintas categorías de equivalencias, de la cual la igualdad es simplemente una de ellas. Si esto tiene sentido entonces el mensaje #= sería una implementación de una categoría de equivalencia determinada y podrían existir distintos mensajes para implementar las otras... suena interesante no? ¿Cómo se definiría una categoría o cuál sería su significado? Dependerá de lo que queramos representar, es una decisión totalmente arbitraria... aunque quizá suene mejor consensuada, consensuada con una comunidad o grupo...
En fin, si les interesa este tema avisen, da mucho para discutir y charlar.

No hay comentarios.: