uqbar-project / wollok-language

Wollok language definition
GNU General Public License v3.0
8 stars 9 forks source link

Cleaner interfaces: Move introspection-related methods to mirror #27

Open nscarcella opened 4 years ago

nscarcella commented 4 years ago

Extracted from discussion on #26 .

Currently, wollok.lang has several methods (mainly in class Object) whose main purpose seems to be the implementation of native behavior. Most of these are not meant to be used by students and having them in lang pollutes the interfaces. So, the proposal is to move these methods to the mirror package, to keep thinks clean.

The methods I'm thinking about these (feel free to comment and add your own):

We also need to define a wollok class for the return of instanceVariables methods (possible InstanceVariable ?) so we can istantiate those on all implementations and not rely on xtext classes.

fdodino commented 4 years ago

Bueno, acabo de migrar los tres primeros métodos:

Los últimos tres no estoy convencido de migrarlos @nscarcella , me parece que nos va a complicar la implementación actual:

  /**
   * Tells whether self object is identical (the same) to the given one.
   * It does it by comparing their identities.
   * So self basically relies on the wollok.lang.Integer equality (which is native)
   */
  method ===(other) = self.identity() == other.identity()

El método identity() no lo estamos usando por el momento, mi única opción para mudarlo a mirror es pasar este método === a nativo, hacer la comparación internamente, y tenerlo en mirror como chiche. Pero no me termina de convencer, no se si @PalumboN @npasserini tienen alguna opinión al respecto.

Después, className lo estamos usando principalmente para excepciones, yo esperaría al refactor de excepciones para tocarlo.

Y por último kindName se usa principalmente en el toString, no estoy seguro de que mirror deba tomar esa responsabilidad y además es cómodo preguntarle a un objeto su kind internacionalizado: un Date o a Date.

Si me dan su ok, yo sigo avanzando este ticket con los 3 primeros métodos y en todo caso abrimos otro para discutir los otros 3 métodos.

nscarcella commented 4 years ago

El tema con identity y kindName es que pueden usarse facilmente para saltear validaciones e implementar, ponele, un switch statement o comportamiento del estilo. En si a mi me gusta la idea de que kindName y etceteras estén en mirror un poco porque me parece consistente y otro poco para ocultarlos. identity por mi pueden volarlo a la goma si quieren poner un native para === me parece bien.

Igual, tampoco es que me voy a desgarrar las vestiduras si prefieren no moverlos. Como les parezca mejor.

fdodino commented 4 years ago

bueno, acá miro a @PalumboN @npasserini nuevamente. Por mí no tengo problemas de hacer estos cambios:

className() por ahora debe quedar, y es lo que deja la puerta abierta a que hagan lo que vos decís, que usen un type testing... por eso tengo opiniones encontradas: me gusta dejar la interfaz de object chica, pero sería naive si pienso que puedo resolver ese problema sin ir a fondo con un refactor de excepciones.

npasserini commented 4 years ago

No sé. Me resultan raras ambas propuestas.

El tema es qué entendemos por identidad, cuál es su objetivo y para qué lo usaríamos. Esto arranca en además en un error histórico que viene de los primeros tiempos de TADP y posiblemente heredado de Java que confunde los términos y usa el equals a veces como igualdad y otras como identidad.

La pregunta entonces es si tiene sentido que un usuario pregunte eventualmente por si dos objetos son el mismo. Si me dejan divagar un toque, para mí la respuesta es sí, y de hecho tiene más sentido, si yo tengo dos objetos Auto, que tienen marca y color como atributos y son de la misma marca y del mismo color. Para el alumno sería natural e intuitivo que fueran iguales, suele causar confusión que eso no pase, en Wollok como en la mayoría de los lenguajes. Entonces, si yo tuviera una colección de misAutos y vos me quisieras preguntar si un auto A es mío, yo quisiera chequear si en mi colección esta ESE auto y no uno igual. Sin embargo las coleciones usan el == y no el ===. El único lenguaje que yo conozca que maneja bien eso y te permite hacer ambas preguntas es Smalltalk (o bueno, al menos Pharo seguro lo tiene).

En, fin, no sé si vale la pena hacerla más larga, nuestra concepción de ==/=== está viciada, y no es un vicio que inventamos nosotros.

Ahora, volviendo, ¿para qué quiero el ===? Yo entiendo que la visión de Fer es identificar objetos que si bien están implementados como instancias físicamente diferentes, queremos que se comporten conceptualmente como si sólo hubiera una instancia única. Por ejemplo en el diagrama. Entonces, por más que tengo dos strings con "Hola" si tengo dos variables apuntando cada una a uno de esos strings, en un diagrama se verían como una única pelota, lo que es conceptualmente más consistente con nuestro discurso.

En un estadío más avanzado, la realidad es que no importa si los strings son iguales o idénticos, porque salvo que hagas cosas muy chanchas, a todos los efectos prácticos ambas cuestiones son indistinguibles. Decir que "son el mismo" es intrascendente para dos objetos cualesquiera que son iguales e inmutables. De hecho,creo que la discusión sobre la identidad podría ahorrarse completamente si los pensamos como valores, un valor no tiene identidad, un string no tiene identidad. No hay una respuesta correcta a si dos unos "son el mismo", el uno es una idea, no tiene identidad. Preguntarse si son el mismo es preguntarse por la implementación y no por el concepto que representan, es una distracción, un desvío.

Pero bueno, asumamos que en una primera instancia es didáctico decir que todos los unos son el mismo, no estoy seguro de que esté bien, pero yo también he dicho eso en clase, supongamos que es una transposición didáctica razonable. Entonces para ser consistente con ese pensamiento, Fer quiere que todos los objetos que representan valores puedan implementar la identidad a su manera y ser representados en un diagrama (o herramientas similares) acorde a su naturaleza.

Lo que quiero decir es que desde esa mirada, un objeto tiene control para decidir sobre si es idéntico o no a otro. No estamos pensando en la identidad como algo "físico" duro, sino conceptual. Lo consistente entonces sería que yo pueda definir nuevos valores y pretender el mismo comportamiento que tienen.

Acá hago un impasse para tratar otra discusión que suele surgir, alguien dirá: "pero es improbable que el estudiante promedio de Obj1/Algo1/Pdep quiera definir un nuevo valor". Yo entiendo que a veces resolver problemas que se alejan del centro de la campana de Gauss nos pone a trabajar en contra de Paretto y encontrarnos problemas que le pegan a un 5% de la gente o menos y que llevan mucho tiempo. Sin embargo, ese pensamiento es peligroso y hay que utilizarlo con austeridad. Por ejemplo, pensando en los problemas de los sets que discutimos hace poco, no me alcanza con que el Set ande bien el 99% de las veces, tiene que ser el 100%. No es negociable.

Este caso puede ser más dudoso, pero la verdad es que me parece importante que el lenguaje sea consistente, al hacer un lenguaje yo creo que tenemos que poner la vara de la consistencia como RNF mucho más alto que en otras aplicaciones, porque vos lo vas a usar de miles de maneras distintas, para construir cosas sobre ellas y que el lenguaje tenga un bug o incluso que sea poco intuitivo, puede ser muy limitante para el que está aprendiendo. No hay nada más frustrante que pasar horas peleando con tu código que no anda para luego descubrir que era un problema de un framework que estabas usando. (Bueno, sí hay cosas más frustrantes, pero esto es mucho muy frustrante.)

Y está bueno que el estudiante avanzado pueda salirse de la caja y pensar cosas, si no la idea de "wollok es un juguete" nos pega muy rápido, pone el techo muy bajo.

Volviendo, yo digo que si nosotros tenemos implementaciones de identidad ad-hoc para nuestros value-objects, lo más consistente es que uno pueda hacer lo mismo para sus propios value-objects, suponiendo que esa consistencia no nos sale muy cara, la mantendría. En principio, la idea de que la identidad sea siempre nativa no me cierra, si vos la sobreescribís yo quiero poder hacerlo también.

Ahora luego, la idea de Nico de llevarlo a mirror, me lleva a dos posibles interpretaciones. La primera es mover la vara de "qué tan flexible es la identidad" al extremo opuesto, y darle una interpretación 100% física y no redefinible. Por eso da pie a sacarlo de los objetos, porque no necesito polimorfismo de algo que no va a tener más de una implementación. Si va a tener múltiples interpretaciones, entonces prefiero que sea un mensaje a los objetos.

La otra interpretación es que hay una parte de la comparación de identidad que está bueno delegarle a un tercero. Por ejemplo preguntar si es de la misma clase, si es null, todas cosas que si yo tuviera que implementar mi propia identidad me daría paja. Entonces está bueno el Mirror.areIdentical(o1,o2) que hace todas esas validaciones y termina delegando en o1 === o2 sii ambos son no nulos y de la misma clase / kind o algo así.

fdodino commented 4 years ago

Bueno, por el momento quedan los 3 métodos en Object. Veremos si el tiempo nos lleva a otro lugar...

npasserini commented 4 years ago

No te la puedo... menos de 20 palabras, decí algo de todo lo que dije!

On Sat, May 9, 2020 at 1:11 PM Fernando Dodino notifications@github.com wrote:

Bueno, por el momento quedan los 3 métodos en Object. Veremos si el tiempo nos lleva a otro lugar...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/uqbar-project/wollok-language/issues/27#issuecomment-626198895, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDLKOOJVEXMM6N5OOERVSTRQV6B5ANCNFSM4JLJ4JOA .

fdodino commented 4 years ago

No entendí por qué tengo que ser yo el que exprese una opinión, habiendo mucha más personas en este proyecto. En todo caso de todo lo que dijiste hay algunas cosas que me quedaron dudas (la confusión sobre el == y el ===, por qué lo sería, si habría que revisar el apunte que habla sobre eso o es exactamente lo que dijiste) y puedo decir que discrepo en 2 cosas:

1) la frase sobre la campana de Gauss tiene que ver con cierta detección de errores de alumn@s que hacen cosas raras, pero desde que lo dije van varias veces que lo mencionás en debates para cosas que yo no lo haría. Ej: un alumno en el 2017 intentó hacer class A inherits A y rompió el IDE. Al toque lo fui a corregir, porque estamos de acuerdo en que es algo que Wollok tiene que soportar más allá de que a nadie más se lo vi hacer. Yo uso la campana de Gauss para errores en donde el a) costo implementativo de resolverlo es grande, b) el costo del error es chico y c) la frecuencia de esa práctica incorrecta es muy baja.

2) "Yo entiendo que la visión de Fer es identificar objetos que si bien están implementados como instancias físicamente diferentes, queremos que se comporten conceptualmente como si sólo hubiera una instancia única." Yo no tengo una visión fuerte al respecto, estaba tratando de resolver el ticket original y necesitaba opiniones respecto a mudar identity(), className() y kindName() a mirror, lo cual representaba un problema implementativo porque se está usando internamente y no sabía qué consecuencias podía tener. Finalmente Nahuel me tiró la idea de subir los cambios que estuvieran hechos, y eso derivó en que el PR se aprobó y el ticket se cerró. Por politeness quise subir un comentario como para indicar que no estaba zanjada la discusión. Lo que voy a hacer es abrirlo nuevamente y esperar a que el resto de su opinion.

npasserini commented 4 years ago

Jajajaja, no, está bien que lo cierres! (O no sé, ni idea, pero confío en tu criterio.) Solamente quería saber tu visión sobre el tema.

On Mon, May 11, 2020 at 8:58 AM Fernando Dodino notifications@github.com wrote:

Reopened #27 https://github.com/uqbar-project/wollok-language/issues/27.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/uqbar-project/wollok-language/issues/27#event-3322630181, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDLKOLSEXRHSZZ7XD3SQP3RQ7R75ANCNFSM4JLJ4JOA .

PalumboN commented 4 years ago

Jajjaja hola, perdón, el rasta llegando tarde :) Tengo esta pestaña abierta hace 8 días!!

Voy a lo práctico (que es lo que iba a contestar hasta el mail de NicoP) como quiere Fer:

PalumboN commented 4 years ago

Ahora, siguiéndo un poco la flasheada de Nico...

Entonces, por más que tengo dos strings con "Hola" si tengo dos variables apuntando cada una a uno de esos strings, en un diagrama se verían como una única pelota, lo que es conceptualmente más consistente con nuestro discurso.

Yo no estoy tan convencido con esto. Bah, si lo extrapolo a, por ejemplo, las fechas no me gustaría que 2 new creen un solo objeto, eso rompe el discurso (teniendo, además, algún literal para las fechas por ejemplo). Por las dudas, aclaro que esto no está pasando ahora: image

Pero esto me despertó un pensamiento que estuve teniendo hace 2 semanas, cuando vi la clase de LeoG introduciendo colecciones y explicando que al hacer [ ] se está creando un objeto nuevo. Nunca me había puesto a pensar en que al escribir varias veces 2 (o algún booleano) en el código se hace referencia al mismo objeto pero al escribir [ ] (o un string) no. No sé, otra mirada podría ser que siempre que escribo 2 estoy hablando con un objeto distinto, pero que no tiene sentido hacer la diferencia (al igual que las fechas, posiciones, strings, etc).

La posta está acá:

De hecho,creo que la discusión sobre la identidad podría ahorrarse completamente si los pensamos como valores, un valor no tiene identidad, un string no tiene identidad. No hay una respuesta correcta a si dos unos "son el mismo", el uno es una idea, no tiene identidad.

Lo consistente entonces sería que yo pueda definir nuevos valores y pretender el mismo comportamiento que tienen.

Tal vez habría que pensar una forma declarativa de decir que un objeto es un valor.

nscarcella commented 4 years ago

Bueno, bueno. A ver...

Un par de cosas antes de hacer referencia a lo que decía Nico.

Yo entiendo que la identidad y la igualdad son importantes por el uso que se le da en las construcciones que vienen con el lenguaje. O sea, si nadie harcodeara el uso de la identidad para nada, sería relativamente fácil de implementar con un atributo id y un mensaje custom esIdenticoA(otro). De hecho, la otra vez decía en la reunión que, si me apurás, la igualdad genérica rara vez tiene sentido en alto nivel porque uno no va por la vida preguntandole a las cuentas corrientes si son iguales al número 3. Es más, si tuviera que definir la igualdad de una cuenta en base a su estado, diría que prefiero un mensaje pertenecenAlMismoCliente que probablemente satisface el mismo fin y no se rompe si agrego otro atributo al modelo.

La razón, entiendo yo, para tener definidos esos contratos (en lugar de permitir que se definan con convenciones ad-hoc) es que el lenguaje los necesita: Las listas tienen que poder decirte si contienen un elemento y permitirte quitarlo y cosas así,. Los sets tienen que garantizar que no esté el mismo elemento dos veces.

Digo esto porque podría ser interesante pensar ¿cómo sería un lenguaje que no hardcodea esas cosas? No se podrían parametrizar esos criterios? Reemplazar el contains(elemento) de la lista por un contains(criterio) y que el #{} use un default basado en igualdad de new Set(criterio)? Ojo no digo no tener igualdad, simplemente usarla para menos cosas, más puntuales.

Meh, no sé. Hay varias cosas de esta indole que siento que uno trae de los lenguajes primigenios y nunca se cuestiona. Capaz es por ahí.

Paso a lo de Nico

La pregunta entonces es si tiene sentido que un usuario pregunte eventualmente por si dos objetos son el mismo. Si me dejan divagar un toque, para mí la respuesta es sí

asfasfasf yo no estoy 100% de acuerdo. Bah, la pregunta "son el mismo" yo la entiendo a nivel mecánico: Onda "¿Ocupan el mismo espacio de memoria?" y "¿Si le cambio un atributo a uno va a cambiar el otro?". Fuera de contexto esta pregunta parece tener sentido pero cómo llega un alumno a esta situación? Quién hizo la pregunta y porqué? Es parte de una pieza de lógica o es el alumno debugueando algo que no se porta como esperaba y, en ese caso, no hay herramientas mejores (cómo el diagrama de objetos) para ver eso?

En un método definido por el alumno yo quisiera que, si aspira a distinguir dos autos que son iguales en términos de color y marca, lo modele el mismo con un campo "patente".

si yo tengo dos objetos Auto, que tienen marca y color como atributos y son de la misma marca y del mismo color. Para el alumno sería natural e intuitivo que fueran iguales, suele causar confusión que eso no pase, en Wollok como en la mayoría de los lenguajes.

Sí, estoy de acuerdo. Si le ponés la igualdad a todos los objetos y no se comporta intuitivamente, para mí resta.

Entonces, si yo tuviera una colección de misAutos y vos me quisieras preguntar si un auto A es mío, yo quisiera chequear si en mi colección esta ESE auto y no uno igual.

Sí, y entiendo que sería engorroso definirle un id a los autos para compararlos. Igual puedo imaginar un mensaje contains(otro) basado en identidad, sobrecargado con un contains(criterio).

En, fin, no sé si vale la pena hacerla más larga, nuestra concepción de ==/=== está viciada, y no es un vicio que inventamos nosotros.

Agree. Aunque no ayuda usar el mismo churumbel que JS usa para la igualdad posta-posta.

Ahora, volviendo, ¿para qué quiero el ===? Yo entiendo que la visión de Fer es identificar objetos que si bien están implementados como instancias físicamente diferentes, queremos que se comporten conceptualmente como si sólo hubiera una instancia única. Por ejemplo en el diagrama. Entonces, por más que tengo dos strings con "Hola" si tengo dos variables apuntando cada una a uno de esos strings, en un diagrama se verían como una única pelota, lo que es conceptualmente más consistente con nuestro discurso.

Sí, yo prefiero eso. Pero el === no hace falta para lograr eso (podría hacerse llamando a Mirror). La pregunta sería si los pibes lo necesitan.

No hay una respuesta correcta a si dos unos "son el mismo", el uno es una idea, no tiene identidad. Preguntarse si son el mismo es preguntarse por la implementación y no por el concepto que representan, es una distracción, un desvío.

De acuerdo.

Pero bueno, asumamos que en una primera instancia es didáctico decir que todos los unos son el mismo, no estoy seguro de que esté bien, pero yo también he dicho eso en clase, supongamos que es una transposición didáctica razonable. Entonces para ser consistente con ese pensamiento, Fer quiere que todos los objetos que representan valores puedan implementar la identidad a su manera y ser representados en un diagrama (o herramientas similares) acorde a su naturaleza. Lo que quiero decir es que desde esa mirada, un objeto tiene control para decidir sobre si es idéntico o no a otro. No estamos pensando en la identidad como algo "físico" duro, sino conceptual. Lo consistente entonces sería que yo pueda definir nuevos valores y pretender el mismo comportamiento que tienen.

Esto no me parece consistente, salvo que esperes que también redefina el identity(). Además, qué vas a hacer si dos objetos dicen que son idénticos y tienen estado interno distinto? Todo bien, pero me parece que si queremos dar soporte para definir valores necesitamos más que un === overrideable.

No sé... Capaz se pueden poner enums si quieren valores o una palabra clave valor para marcar una clase u objeto que no te deje tener atributos variables y maneje la unicidad de la instanciación por atrás (simil case clases).

De todos modos me parece que el lenguaje ya te da herramientas si querés tener la misma bolita en el diagrama... Hay constantes a nivel de package si querés hacer WKOs y también tenés la posibilidad de crear singletons. Cuanto más lo pienso menos me gusta pisar el ===.

está bueno que el estudiante avanzado pueda salirse de la caja y pensar cosas, si no la idea de "wollok es un juguete" nos pega muy rápido, pone el techo muy bajo.

Sísí, por eso propongo mover estas cosas a Mirror. Así identifico al estudiante avanzado y se lo muestro, en lugar de que los no tan avanzados se la den en la pera. Qué se yo... No era esa la idea de mirror? Limpiar la interfaz de cosas que perjudiquen a los pibes a la izquierda de la campana.

Volviendo, yo digo que si nosotros tenemos implementaciones de identidad ad-hoc para nuestros value-objects, lo más consistente es que uno pueda hacer lo mismo para sus propios value-objects, suponiendo que esa consistencia no nos sale muy cara, la mantendría. En principio, la idea de que la identidad sea siempre nativa no me cierra, si vos la sobreescribís yo quiero poder hacerlo también.

Yo no estoy convencido. No me cierra la identidad como concepto desprendido completamente de lo nativo. Si pregunto por identidad en lugar de por igualdad u otro mensaje de dominio estoy pensando en una distinción que en algún nivel impacta la representación (si cambio uno cambia el otro).