uqbar-project / wollok-language

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

Unificar sintaxis de linearización #53

Closed nscarcella closed 3 years ago

nscarcella commented 4 years ago

@fdodino @npasserini @PalumboN Buenas y santas,

Ahora mismo tenemos dos sintaxis diferentes para la linearización de mixines en dos lugares distintos del lenguaje:

En las entidades nombradas (por ejemplo, las clases) usamos la palabra clave mixed with para el primer mixin, seguida de and como separador para las demás:

ClasesNombradas

Ej:

  clase MiClase mixed with MiMixin and MiOtroMixin

Por otro lado, en las clases anónimas que se crean producto de linearizar una clase al hacer new usamos la palabra clave with:

ClasesAnónimas

Ej:

new MiOtraClase() with MiMixin with MiMixin

Imagino que esta diferencia es más bien producto de un descuido y no tiene ningún propósito, pero hace la gramática innecesariamente compleja y me gustaría que optemos por tener la misma notación en todos los casos.

Dicho eso, quisiera proponer el envión para que nos deshagamos de la palabra clave mixed with porque son dos palabras y eso nos atormenta a mi y a mi lexer pero sobre todo porque no está conjugada de la misma forma que inherits y el texto termina sugiriendo que es la superclase la que está mixeada y no la clase que definís:

class MyClass inherits Other mixed with Something

Qué se yo... Podríamos usar la palabra mixing.

También me perturba un poco que and es al mismo tiempo un separador de mixines y un alias del operador &&, pero bue... No me quiero ir por las ramas.

Sé que estamos medio anticipando algún overhaul de las Clases y los Mixines, pero siendo que eso no está ni definido todavía y este es un cambio bastante sencillo podría estar bueno para meter en el próximo release que suba el mayor de la versión.

La otra diferencia importante de sintaxis es la que tenemos en el inherits de los singletons:

object miObjeto inherits MiClase(p1, p2) with MiMixin

Si eliminamos los constructores, esa linea debería ser:

object miObjeto inherits MiClase(arg1 = p1, arg2 = p2) with MiMixin

Yo propongo que también dejemos pasar parámetros al linearizar el mixin:

object miObjeto inherits MiClase(arg1 = p1, arg2 = p2) with MiMixin(argDelMixin = otraCosa)
fdodino commented 4 years ago

A mí me gusta mixing y de paso me gustaría ver si podemos tratar de tener una definición que simplifique el entendimiento de la linearización, algo como

class MyClass mixing Mixin1 and Mixin2 and Mixin3 inherits Superclass

La idea ya la tuvo Javi en este issue. Yo estoy muy interesado porque lo estoy dando en Algoritmos 2 (UNSAM) y los pibes se copan mucho más con los mixines de Wollok que con el decorator.

nscarcella commented 4 years ago

Está bueno ese orden porque puede leerse fácil de mayor a menor "precedencia" (?):

class MyClass mixing Mixin1 and Mixin2 inherits Superclass

Donde cuanto más a la izquierda (más rojo) está una entidad, mayor prioridad tiene en el method lookup.

Por otro lado, si fueramos a usar ese orden mixing ... inherits ya no está bien conjugado de nuevo, en todo caso podríamos decir mixes. También creo que en la bibliografía académica (ponele, Bracha http://www.bracha.org/jigsaw.pdf) no les tiembla el pulso en decirle inheritance a la linearización de mixins y meterlos en la misma bolsa con las clases, con lo cual podría ser una opción razonable usar la misma palabra clave y poner un chequeo blando de que la superclase puede ser una sola:

class MyClass inherits Mixin1 and Mixin2 and Superclass

Esto tiene la ventaja de que presenta una sintáxis homogenea y pavimenta el camino a una posible transición de Mixins+Classes a Roles.

A mí, personalmente, siempre me gustaron mucho más los lenguajes que usan churumbeles para esto, (en particular me gusta el <: que suele usarse para indicar subtipado:

class MyClass <: Mixin1 <: Mixin2 <: Superclass

Un poco porque envejece mucho mejor que cualquier palabra que elijas y otro poco porque cada uno puede asociarle la palabra con la que se sienta cómodo.

Pero bue, tampoco quiero asustar a nadie, con que usemos la misma sintáxis en las clases y el new me conformo.

N.

El lun., 13 jul. 2020 a las 11:38, Fernando Dodino (< notifications@github.com>) escribió:

A mí me gusta mixing y de paso me gustaría ver si podemos tratar de tener una definición que simplifique el entendimiento de la linearización, algo como

class MyClass mixing Mixin1 and Mixin2 and Mixin3 inherits Superclass

La idea ya la tuvo Javi en este issue https://github.com/uqbar-project/wollok/issues/536. Yo estoy muy interesado porque lo estoy dando en Algoritmos 2 (UNSAM) y los pibes se copan mucho más con los mixines de Wollok que con el decorator.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/uqbar-project/wollok-language/issues/53#issuecomment-657599568, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPE25DPWFDDTCEQIK2YVLR3ML7HANCNFSM4OYEUKUQ .

fdodino commented 4 years ago

Sí, esa sintaxis loca de tener inherits que sea tanto de mixins como de clases la tiene Python, una de las cosas que me parecieron simpáticas. De todas maneras, no se, no me termina de convencer hacer el salto tan grande, preferiría hacer baby steps...

fdodino commented 4 years ago

Ah, y le saqué la tilde a la sintaxis, me ponía mal. :smile:

nscarcella commented 4 years ago

Así se pierden los mails...

Lo malo de los baby steps es que cada step nos hace migrar, pero sin presiones. Usemos la sintaxis que prefieran, pero elijamos una sola para el new y las clases.

El lun., 13 jul. 2020 a las 13:47, Fernando Dodino (< notifications@github.com>) escribió:

Ah, y le saqué la tilde a la sintaxis, me ponía mal. 😄

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/uqbar-project/wollok-language/issues/53#issuecomment-657669940, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPE232TISAKY3N434LMX3R3M3BVANCNFSM4OYEUKUQ .

PalumboN commented 4 years ago

+1 a unificar los mix y reordenar las definiciones de las clases para que acompañen la linearización.

De las propuestas que tiraron todas me agradan. Mir preferencias son:

PalumboN commented 4 years ago

En la reunión estuvimos hablando de propuestas para que la sintaxis refleje la linearización:

// ESTO SERÍA LO IDEAL
// -->
class MyClass mixing? Mixin1 and? Mixin2 inherits Superclass
// -->
var obj = new MiMixin1 and? MiMixin2 mixed? MiOtraClase()
// -->
var obj = object mixing Mixin1 and Mixin2 and Mixin3 inherits Superclass { method m() { .. } }

// ESTAS FUERON OTRAS IDEAS CONTROVERSIALES
// ???
var obj = new MiOtraClase() mixed? MiMixin1 and? MiMixin2
// <--
var obj = new MiOtraClase() mixed? MiMixin2 and? MiMixin1
isaiaslafon commented 4 years ago

alternative to: class MyClass mixing? Mixin1 and? Mixin2 inherits Superclass

class MyClass mixed Mixin1 also Mixin2 inherits Superclass class MyClass mixedWith Mixin1 also Mixin2 inherits Superclass

nscarcella commented 4 years ago

Bueno, de la reunión de roadmap surgió la propuesta de eliminar la sintaxis que permite linearizar mixines en el new, aprovechando que es la más problemática y no permite hacer nada que no puedas hacer con un object anónimo:

// Esto
const anónimo = new Superclase(arg1 = p1, arg2 = p2) with M2 with M1

//es actualmente equivalente a esto
const anónimo = object inherits Superclase(arg1 = p1, arg2 = p2) mixed with M2 with M1

Donde en ambos casos M1 tiene mayor "precedencia" que M2 en el method lookup. Hay que tener en cuenta que preferimos la opción de object porque permite definir métodos, mientras que el new no, con lo cual no tiene sentido para nada que no sea linearizar mixines:

// Esto vale
const anónimo = object inherits Superclase(arg1 = p1, arg2 = p2) mixed with M2 with M1 {
  method piola() = 1
}

//Esto no
const anónimo = new Superclase(arg1 = p1, arg2 = p2) with M2 with M1 {
  method piola() = 1
}

La idea es tratar de buscar la alternativa que mejor se acomode a las siguiente wishlist (ordenada por prioridad dada en la reunión):

  1. Tener una sintaxis homogénea para los 5 casos de linearización y herencia, a saber:
    • clases nombradas
    • mixines
    • singletons nombrados
    • literales de singletons anónimos (con y sin herencia o mixines)
    • instanciación de clases anónimas (Este proponemos volarlo)
  2. Reflejar la precedencia de linearización en el orden de la sintáxis (esto es, (Clase/Singleton definido) > Mixin1 > ... > MixinN > Superclase
  3. Que la notación sea expresiva y verbosa pero bien conjugada para todas las combinaciones posibles
  4. Evitar palabras clave con espacios

Mis propuestas entonces, que hasta dónde entiendo cumplen todos esos requisitos, son las siguientes:


OPCION 1: Unificar la palabra que usamos para incluir clases y mixins, linearizando de derecha a izquierda Esta me parece la opción más consistente que al mismo tiempo no se aleja tanto de lo que tenemos ahora. Básicamente todos los casos son iguales, sin importar si usas clases o mixines, con lo cual es muy fácil de recordar y no deja lugar a ambiguedades.

Usar "inherits" independientemente de si es una clase o módulo podría hacerle ruido a alguien pero, cómo mencioné arriba, a los autores académicos no parece temblarles el pulso al hablar de "heredar" mixins. También tiene la ventaja de que facilita una eventual unificación de clases y mixins. Si esto les resulta inaceptable, pasen a la OPCION 2.

La linearización de derecha a izquierda respeta el orden de linearización, tomando el cuerpo de la clase como lo más prioritario, luego los mixines en el mismo orden que los tenemos ahora (lo cual facilita migrar el código actual...) y finalmente la superclase.

Finalmente, los parámetros (que en todos los casos son opcionales) se pasan tanto para clases como mixines. Si algún atributo estuviera definido en más de un lugar, habría que pasarselo a la construcción de más a la derecha.

// CLASES
// Con todo
class Clase inherits SuperClass(arg1 = p1, arg2 = p2) and M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
class Clase inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
class Clase inherits M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
class Clase { method m() {...}  }

// MIXINS
// Con mixins
mixin Mixin inherits M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
mixin Mixin { method m() {...}  }

// SINGLETONS NOMBRADOS
// Con todo
object Singleton inherits SuperClass(arg1 = p1, arg2 = p2) and M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
object Singleton inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object Singleton inherits M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
object Singleton { method m() {...}  }

// SINGLETONS ANÓNIMOS
// Con todo
object inherits SuperClass(arg1 = p1, arg2 = p2) and M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
object inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object inherits M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
object { method m() {...}  }

// NEW DE CLASES ANÓNIMAS
// Se descarta en favor del singleton

OPCION 2: Igual a la OPCION 1, pero usando extends en lugar de inherits Esta opción es básicamente por si decidimos que es inaceptable decir que "heredamos" mixins. Basicamente reemplaza inherits por otra palabra (también única para los dos). Le puse extends ... with porque sí (bah, se usa en Scala, qué se yo) pero podría ser cualquier otra palabra. El punto es hacer más foco en la idea de que se están linearizando las cosas que vienen a continuación y menos en qué mecánica se usa para linearizarlas. Una pequeña ventaja de esta variante es que "extends ... with" sugiere que el orden de linearización es de derecha a izquierda, con lo cual no hace falta recordar nada.

Honestamente, esta es la opción que más me gusta, aunque sea un poco más diferente a la sintaxis actual.

Si distinguir entre mixear y heredar es super importante pasen mejor a la opción 3.

// CLASES
// Con todo
class Clase extends SuperClass(arg1 = p1, arg2 = p2) with M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
class Clase extends SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
class Clase extends M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sin nada
class Clase { method m() {...}  }

// MIXINS
// Con mixins
mixin Mixin extends M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sin nada
mixin Mixin { method m() {...}  }

// SINGLETONS NOMBRADOS
// Con todo
object Singleton extends SuperClass(arg1 = p1, arg2 = p2) with M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
object Singleton extends SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object Singleton extends M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sin nada
object Singleton { method m() {...}  }

// SINGLETONS ANÓNIMOS
// Con todo
object extends SuperClass(arg1 = p1, arg2 = p2) with M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
object extends SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object extends M2(arg3 = p3) with M1(arg4 = p4) { method m() {...}  }
// Sin nada
object { method m() {...}  }

// NEW DE CLASES ANÓNIMAS
// Se descarta en favor del singleton

OPCION 3: Mantener palabras diferentes para linearizar clases y mixins, linearizando de derecha a izquierda Esta opción es la más conservadora: Mantiene el orden de linearización y conserva dos palabras diferentes para mixins y clases. Para mi, que advoco por unificar la idea de clase y mixin, hacer hincapie en la distinción entre herencia y mixeo no tiene mucho valor, pero tampoco voy a razgarme las vestiduras si todos prefieren ir por este lado.

La propuesta entonces es mantener inherits para la superclase y reemplazar mixed with ... and y with por mixes ... and en todos los casos. Los dos verbos están conjugados en el presente del indicativo para ser consistente, pero admito que la frase suena rara porque le falta un "and" en el medio que no estoy poniendo porque LA GENTE DE BIEN NO USA KEYWORDS CON ESPACIOS.

// CLASES
// Con todo
class Clase inherits SuperClass(arg1 = p1, arg2 = p2) mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
class Clase inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
class Clase mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
class Clase { method m() {...}  }

// MIXINS
// Con mixins
mixin Mixin mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
mixin Mixin { method m() {...}  }

// SINGLETONS NOMBRADOS
// Con todo
object Singleton inherits SuperClass(arg1 = p1, arg2 = p2) mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
object Singleton inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object Singleton mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
object Singleton { method m() {...}  }

// SINGLETONS ANÓNIMOS
// Con todo
object inherits SuperClass(arg1 = p1, arg2 = p2) mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sólo superclase
object inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }
// Sin nada
object { method m() {...}  }

// NEW DE CLASES ANÓNIMAS
// Se descarta en favor del singleton

VARIANTE TRANSVERSAL: Orden de Izquierda a Derecha

Esta variante puede aplicar a cualquiera de las 3 opciones de arriba y consiste, básicamente en invertir el orden de linearización para que sea de izquierda a derecha en lugar de de derecha a izquierda.

Entonces, tomando la opción 3 como referencia, en lugar de:

class Clase inherits SuperClass(arg1 = p1, arg2 = p2) mixes M2(arg3 = p3) and M1(arg4 = p4) { method m() {...}  }

quedaría

class Clase mixes M1(arg1 = p1) and M2(arg2 = p2) inherits SuperClass(arg3 = p3, arg4 = p4) { method m() {...}  }

Pongo esto como variante porque me parece menos consistente que lo otro, porque los métodos de la clase quedan del lado "equivocado" de la linearización (se supone que son lo que más precedencia tiene, pero quedan al final). Seguramente hay alguna excepción, pero creo que todos los lenguajes hacen esto al revés. Pero bueno, si les copa mucho esta forma, no me opongo.


En fin, estaría bueno que opinen por dónde les parece que va la cosa.

fdodino commented 4 years ago

Pongo esto como variante porque me parece menos consistente que lo otro, porque los métodos de la clase quedan del lado "equivocado" de la linearización (se supone que son lo que más precedencia tiene, pero quedan al final).

No entendí esta parte, ¿vos decís el método m?

Yendo a tu pregunta, la idea de definir la clase y luego linearizar de derecha a izquierda me deja tranquilo.

De las tres opciones, la 1 es la que más me gusta, preferiría no afectar el inherits que ya existe (parece una pavada pero cambiarlo por extends rompería un montón de ejemplos, documentación, gifs, apuntes), mientras que dejar el inherits toca solo la página de mixins y muchos menos ejemplos (me parecía simpática la opción 2 pero el esfuerzo que nos demanda me parece que no vale la pena, y Kotlin/Python son dos ejemplos en donde no les calienta mucho la idea de que no se mezclen interfaces, mixins o clases).

Y una maravilla @nscarcella tu análisis. Impresionante laburo!

nscarcella commented 4 years ago

Pongo esto como variante porque me parece menos consistente que lo otro, porque los métodos de la clase quedan del lado "equivocado" de la linearización (se supone que son lo que más precedencia tiene, pero quedan al final).

No entendí esta parte, ¿vos decís el método m?

Claro. Los métodos que define la clase son los que overridean todo lo demás, entonces la opción de derecha a izquierda me suena más prolija. Igual insisto en que no me vuelve loco, pero es un detalle.

De las tres opciones, la 1 es la que más me gusta, preferiría no afectar el inherits que ya existe (parece una pavada pero cambiarlo por extends rompería un montón de ejemplos, documentación, gifs, apuntes)

Por eso es la uno ;)

No me parece una pavada. Más allá de que estemos aumentando el mayor, un cambio groso de sintaxis hace una ola de laburo. En algún momento me gustaría tratar de armar algo para automatizar migraciones de una versión del lenguaje a la siguiente, pero vamos de a poco...

me parecía simpática la opción 2 pero el esfuerzo que nos demanda me parece que no vale la pena Sí, me pasa un poco lo mismo. Podemos guardarnos esa notación por si en algún momento metemos los roles. Así podríamos tenerlos en paralelo con clases y mixines deprecados hasta que la gente se aclimate. Pero de nuevo, no nos adelantemos, con tener una sintaxis homogénea soy feliz.

asanzo commented 4 years ago

¡Hola! Perdón por faltar a las meetings de roadmap, se me pasó el mail y no las tenía en mente. Che, Nico, qué guasada de análisis, , por favor unifiquemos el tema de constructores siempre con parámetros nombrados. Y muchas gracias por traer el tema de ser consistentes con la forma de mixinear en cada caso de linearización y herencia.

Estoy intentando interiorizarme, porfa disculpen si la cago, quiero aprender:

Nota: Creo que es importante algo que vos decís al pasar, Nico, que son los roles. Es toda la diferencia. Si vamos por los roles, opción 2 (¿o quizás con otra palabra que no sea extends? Había un issue al respecto). Sino vamos por la 1 o la 3 (me gusta más la 3). Entonces, suponiendo que no vamos a enseñar roles:

No me gusta la opción 1 porque:

class Golondrina inherits Animal and Volador and Emplumado`

Siendo Volador y Emplumado mixines y Animal una clase, parece como que son las tres cosas lo mismo, cuando técnicamente la relación entre Golondrina y Volador es más "flexible" que la de Golondrina y Animal. Y entender esa diferencia es importante a la hora de modelar (de hecho, siguen valiendo las discusiones de la clase de "herencia vs composición" sobre las limitaciones de la herencia, a la hora de elegir qué es un mixin y qué es una clase)

Entonces, propongo opción 3b, con una ligera derivación, para reforzar que cada cosa que agregás es un mixin:

class Golondrina inherits Animal mixes Volador mixes Emplumado`

Aunque la opción 3 de Nico "pura" también podría ir, no me desvivo por el and :smile:

nscarcella commented 4 years ago

El dom., 9 ago. 2020 a las 16:49, asanzo (notifications@github.com) escribió:

¡Hola! Perdón por faltar a las meetings de roadmap, se me pasó el mail y no las tenía en mente. Che, Nico, qué guasada de análisis, , por favor unifiquemos el tema de constructores siempre con parámetros nombrados. Y muchas gracias por traer el tema de ser consistentes con la forma de mixinear en cada caso de linearización y herencia.

Estoy intentando interiorizarme, porfa disculpen si la cago, quiero aprender:

  • Sobre el orden de linearización y la pregunta que hizo Fer, no estaba mirando el método m, sino la clase Clase. Por eso prefería de izquierda a derecha: class Golondrina zaraza Volador zaraza Animal para mí significaba "sacá los métodos primero de Golondrina, luego de Volador y luego de Animal". Pero visto como lo proponés vos: class Golondrina zaraza Animal zaraza Volador { métodos } puedo explicarlo como "La Golondrina toma sus métodos primero, y luego los de Volador y luego los de Animal, leyendo de derecha a izquierda (pasa que yo los métodos no los veía "a la derecha", sino "abajo"). En resumen, soy feliz con cualquiera de las dos (lo cual me hace preguntarme cómo es en la industria) (¿Cómo es en la industria? 😅)

Claro, tomar el nombre de la entidad en lugar del cuerpo te deja invertir el orden (de ahí la última variante que propongo), el problema es que ese enfoque "nominal" (?) es medio flojo para las entidades anónimas. Igual, sí. A mi me pasa igual, cualquier cosa que sea consistente me cierra.

Acá alguien con más calle que yo me puede desasnar, pero entiendo que la notación de Derecha a Izquierda es la favorita de la industria. Scala y Kotlin lo hacen así. Ruby lo hace adentro del cuerpo directamente, pero también se lee de "abajo para arriba".

Nota: Creo que es importante algo que vos decís al pasar, Nico, que son los roles. Es toda la diferencia. Si vamos por los roles, opción 2 (¿o quizás con otra palabra que no sea extends? Había un issue al respecto). Sino vamos por la 1 o la 3 (me gusta más la 3). Entonces, suponiendo que no vamos a enseñar roles:

Ojo, acá yo creo que si fuesemos a meter roles capaz convendría tenerlo en paralelo con clases y mixins deprecados un tiempo, para dar chances de conocer y migrar. En ese sentido convendría guardarse la notación para roles y eventualmente deprecar la otra.

  • De acuerdo con dejar el inherits. Es una palabra que usamos mucho ("hereda") y me parece que el caso para el que más se usa Wollok (intro a objetos) amerita que quede ahí (sobretodo si la herencia sigue siendo parte de nuestro bastión de batalla).
  • Además, siento que mientras exista una diferencia entre las relaciones de "mixea" y "hereda" (por ejemplo, no poder heredar de más de una clase pero sí mixear más de un mixin) quiero las palabras distintas.

No me gusta la opción 1 porque:

class Golondrina inherits Animal and Volador and Emplumado`

Siendo Volador y Emplumado mixines y Animal una clase, parece como que son las tres cosas lo mismo, cuando técnicamente la relación entre Golondrina y Volador es más "flexible" que la de Golondrina y Animal. Y entender esa diferencia es importante a la hora de modelar (de hecho, siguen valiendo las discusiones de la clase de "herencia vs composición" sobre las limitaciones de la herencia, a la hora de elegir qué es un mixin y qué es una clase)

A mi este argumento no me convence tanto. No siempre querés una palabra especial para cada cosa que no es exactamente lo mismo, a veces querés, justamente, concentrarte en cómo esas cosas se pueden tratar indistinto. Por ejemplo, no te calienta usar la misma palabra para heredar de clases abstractas y clases concretas, a pesar de que tiene implicancias muy fuertes en qué métodos vas a tener que definir o no. Respecto de la diferencia entre clases y mixines para mi es similar. El compilador no va a dejarte poner más de una clase en la linearización, ni poner la clase antes que los mixines, con lo cual usar palabras distintas es medio un capricho que hace más foco en distinguir un detalle que se usa por atrás.

Ojo, igual cuando digo capricho puede sonar muy negativo, para mi está bien si es lo que queremos. Lo que yo creo es que no es una distinción muy valiosa, pero estoy dispuesto a ceder.

Entonces, propongo opción 3b, con una ligera derivación, para reforzar que cada cosa que agregás es un mixin:

class Golondrina inherits Animal mixes Volador mixes Emplumado`

Aunque la opción 3 de Nico "pura" también podría ir, no me desvivo por el and 😄

No me molestan las diferencias. Lo único que me interesa es que sea homogéneo.

— 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/53#issuecomment-671093583, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPE22U5ECH2PXNQ4IL27DR734WFANCNFSM4OYEUKUQ .

fdodino commented 4 years ago

Hola @asanzo , solo puedo agregar que el único "distinto" es Python: https://www.ianlewis.org/en/mixins-and-python, respecto a que va de izquierda a derecha. Pero igualmente tiene una sintaxis que a mí no me gusta, como pasa con Kotlin, los chirimbolos a mí no me parecen copados si estamos en una materia inicial. A NicoS le encantan pero logramos negociar ese punto. El viernes que viene 14/08 a las 19:00 nos juntamos para seguirla, lo importante es que leamos este ticket y podamos tomar una decisión para implementarlo. Respecto a los roles, nos pareció que para poder avanzar con esa definición necesitamos un % grande de consenso y no da para definirlo si somos 4 ó 5 nomás. Si aumenta el número es otro cantar. Abrazo Fer

nscarcella commented 4 years ago

Cierto. Pyton prioriza de izquierda a derecha.

También es un caso interesante, porque lo que tiene se parece más a Roles (o bueno, herencia multiple) que a mixins. Si se fijan los mixines se definen usando la palabra class, como cualquier otra clase. Esto un poco refuerza la idea de que las palabras "clase", "Mixin" y "herencia" la industria se las pasa bastante por el culo.

Aguanten los chirimbolos.

N.

El dom., 9 ago. 2020 a las 19:43, Fernando Dodino (notifications@github.com) escribió:

Hola @asanzo https://github.com/asanzo , solo puedo agregar que el único "distinto" es Python: https://www.ianlewis.org/en/mixins-and-python, respecto a que va de izquierda a derecha. Pero igualmente tiene una sintaxis que a mí no me gusta, como pasa con Kotlin https://stackoverflow.com/questions/48391217/extend-and-implement-at-the-same-time-in-kotlin, los chirimbolos a mí no me parecen copados si estamos en una materia inicial. A NicoS le encantan pero logramos negociar ese punto. El viernes que viene 14/08 a las 19:00 nos juntamos para seguirla, lo importante es que leamos este ticket y podamos tomar una decisión para implementarlo. Respecto a los roles, nos pareció que para poder avanzar con esa definición necesitamos un % grande de consenso y no da para definirlo si somos 4 ó 5 nomás. Si aumenta el número es otro cantar. Abrazo Fer

— 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/53#issuecomment-671109684, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPE23JV3XJJFS6KX3RIO3R74RAXANCNFSM4OYEUKUQ .

javierfernandes commented 4 years ago

Buenas. Aporto 3 cosas: algo de historia, algo de experiencia y una opinión.

Historia (se puede skipear)

Las inconsistencias de sintaxis no son producto de un descuido sino mas bien de limitaciones por ambigüedad (si no me equivoco, ya pasaron fácil como 3 o 4 años desde que implementé los mixins) de la gramática de XText. O bueno, si quieren una limitación mía para desambigüar eso en la gramática. Obviamente no recuerdo los detalles.

El tener una keyword compuesta fue más bien una lucha interna de "1 única keyword pero que produzca un texto pseudo inglés-indio confuso" como pasa hoy con "inherits" que es justamente por lo que nunca me gustó (técnicamente debería ser "inherits FROM" para ser correcto), versus usar 2 palabras, que sea más humanamente legible, y bancarse eso a nivel técnico (después de todo el IDE te debería ayudar a no tener que tipear eso). Salvo que me esté perdiendo algún otro problema más fuerte conceptual de keywords multi palabra. Particularmente los verbos para expresar la relación con mixines son bastante chotos. "Mezcla" ? "se mezcla" ? "es mezclado" ? Dependen de la dirección de la expresión (léase quién es el sujeto, objeto etc) y suelen requerir 2 palabras.

La dirección actual es la de Scala, y además de hacer más dificil decidir una keyword tiene el problema del orden, como decía en el issue original. Eso me lleva a ...

Experiencia de enseñar mixins con Scala:

En O3 de UNQ expliqué mixines por varios años, y SIEMPRE se daba la misma confusión al explicar cómo escribir y ppalmente LEER la sintaxis de mixins de Scala. Había 2 problemas para los cuales mi conclusión siempre fue "no es natural esta sintaxis" y es extremadamente confusa artificialmente (como tantas otras cosas de ruby, por ej).

1) El uso de "extends" para clases y mixines.

En Scala extends se usa para clases, como para mixins. Pero no siempre ! Depende de si mi texto declara una superclase o no ! Ej (A y B son clases, Mn son mixines)

class B extends A with M1 
class B extends M1
class B extends M1 with M2

Para mí esto es superconfuso en un metamodelo que tiene clases y mixines ! O sea, entiendo y me parece seductora la idea de unificar conceptos, pero el camino ahí es borrar las clases, no esconderlas bajo una misma sintaxis. Y de última lo importante de fondo parecen ser las implicancias profundas de borrar las clases y trabajar sólo con mixins, más que la sintaxis. Mientras el lenguaje mantenga clases, es decir no plantee una forma radicalmente distinta de modelar comportamiento y trate a clases y a mixines de forma particular, para mí suena más claro diferenciar la forma de uso. Ok, en cuanto a la herencia podrían considerarse iguales, pero me suena a una unificación de conceptos parcial que termina siendo más académica que práctica y confundiendo al principiante.

El problema se puede resumir a que cuando uno arranca a explicar un concepto se espera tener esta forma: "los mixines son blah.. y los uso con esta sintaxis (una)". Si en cambio eso es "se usan igual que una superclase... si estoy declarando sólo un mixin, pero, si ya declaro superclase, se usan de esta otra forma, y ... si uso ambas tengo que volver a la forma de mixins y usar extends para la clase". Es medio una confusión.

2) El orden

Segundo problema que requería dedicarle vaaarios minutos sólo para explicar "cómo leerlo" porque no es intuitivo. Me parece que uno espera y desea poder ver en el código la linea de herencia, porque te evita un procesamiento mental recurrente de reordenar las cosas que estas viendo. En la sintaxis de Scala (copiada por wollok), está ese problema. Veo varios para hilar más fino. En dibujito se ve mejor. image (omito keywords)

Véase como hay que separar lo que se lee en 2 pasos para armar la herencia (pegar saltos al leer):

Bastante confuso teniendo en cuenta que al final se arma una linea (exceptuemos herencia entre mixins).

Hay un 3er problema (además de tratar mentalmetne distinto a las clases, y luego reordenar los mixines) como bien dijeron sobre la duplicidad del concepto de la clase misma, porque aparece su nombre y su cuerpo. Para mí ahí no hay muchas opciones sin cambiar radicalmente la forma de declarar clases hacia algo que no me convence del todo,...

//      <----------      lookup    ----------
SuperClass mixed (with?) M1 and M2 and M3 derives class MiClase { .... métodos }

BTW esto se parece a mandarle mensajes a la super clase de smalltalk para declarar/crear una clase. Resuelve el orden en un 100%, pero bueno, es bastante controversial. Entonces en ppio yo me bajaría de la idea de unificar el cuerpo del método.

Vuelvo. Entiendo que todas las propuestas numeradas de NicoS mantienen ese tratamiento especial para las clases vs mixines. Y por eso la idea que más me gustaba (y acá mi opinión) era esta, que creo que es la que NicoS menciona como "variante transversal" al final.

image

Me parece que es la que menos procesamiento mental requiere al lector. También uno puede pensar en las interacciones futuras, no pensando en que el que codea ya sabe exacto la linea que va a escribir. O bien que sufre refactors. Quizás arranco con

Clase inherits [from] SuperClase
// luego extraigo algo a un mixin toco expresando explícitamente cómo modifico la linea

Clase [mixes M1] inherits SuperClase

// y si agrego más, toco en el lugar que quiero afectar a la cadena DIRECTO: antes y después de M1 (las keywords medio que cagan)
Clase [mixes M0] mixes M1 [mixes M2] inherits SuperClase

Es un problema de sábana corta con los editores de textos tradicionales. Porque tener keywords más legibles como "and" "with" etc, maximizan la legibilidad pero al costo de luego tener que modificar cuando meto cambios. Idealmente un editor proyectivo/estructurado podría solucionar eso :P

Bueno, eso. Estoy completamente out de wollok hace varios años, pero vi esta discusión de refilón y quería apoyar la moción de cambio, porque como dije cada vez que expliqué este tema con Scala debía dar una "mecánica mental accesoria" para que los alumnos reformulen la linea de herencia.

Vuelvo al laburo :P Saludos !

PD: la mayoría de los lenguajes hacen cualquier con los mixins, porque nadie quiere romper las bases de las clases. Tal vez lo más interesante sería estudiar Self, que creo que es el único que lo hace bien y de hecho de donde nació la idea si no me equivoco.

lspigariol commented 4 years ago

Poniendome en el lugar de un estudiante que conoce herencia y querer aprender mixins, (no tengo que hacer mucho esfuerzo ya que es mas o menos mi situacion...), coincido en primer lugar con el planteo de Alf

Sobre el orden de linearización y la pregunta que hizo Fer, no estaba mirando el método m, sino la clase Clase. Por eso prefería de izquierda a derecha: class Golondrina zaraza Volador zaraza Animal para mí significaba "sacá los métodos primero de Golondrina, luego de Volador y luego de Animal ". (pasa que yo los métodos no los veía "a la derecha", sino "abajo").

Cuando veo una herencia comun class Ave inherits Animal { } lo leo de izquierda a derecha. (Los mixins esperaria leerlos igual)

Respecto de los terminos, prefiero los de una sola palabra, como quiere Nico. Retomando en parte lo que decia Javi que al inherits le faltaría el from, es aceptable usar un "mixes" sin with. Para enumarar los mixines, prefiero la coma antes que el and o repetir el with. Da mas idea de secuencia o serie, mientras que el and suena booleano. Tambien me cierra lo de repetir el mixes delante de cada mixin.

Como dice Fer, a esta altura no cambiaría el inherits por otro termino.

Acuerdo con quitar el new y dejar el object en sus dos formas (var x = object inhertis/mixes... y object x inherits/mixes... )

hasta acá, es el asunto .....................................

Ahora, respecto de unificar terminos/conceptos, no tengo tan clara la diferencia como para opinar, pero me pregunto:

La diferencia entre trabajar con mixines o clases, está dada por la diferencia en sí de un mixin o una clase, o por el tipo de relación diferente que sugiere heredar o mixear? En otras palabras, que es lo que tiene mas sentido: ¿tener solo inherits, pero que dependiendo que sea de un mixin o una clase signifique cosas distintas? (esta seria la opcion 1 de nico?) ¿o pensar que existen las clases, que pueden declararse o no como abstractas, (y no los mixines) manteniendo las diferencias entre mixear y heredar ?

por otra parte, imaginando la existencia de una herencia multiple, si tuvieramos class A inherits B inherits C ¿que tendria de diferente con class A mixes B mixes C ?

El lun., 10 de ago. de 2020 a la(s) 12:36, Javier Fernandes ( notifications@github.com) escribió:

Buenas. Aporto 3 cosas: algo de historia, algo de experiencia y una opinión. Historia (se puede skipear)

Las inconsistencias de sintaxis no son producto de un descuido sino mas bien de limitaciones por ambigüedad (si no me equivoco, ya pasaron fácil como 3 o 4 años desde que implementé los mixins) de la gramática de XText. O bueno, si quieren una limitación mía para desambigüar eso en la gramática. Obviamente no recuerdo los detalles.

El tener una keyword compuesta fue más bien una lucha interna de "1 única keyword pero que produzca un texto pseudo inglés-indio confuso" como pasa hoy con "inherits" que es justamente por lo que nunca me gustó (técnicamente debería ser "inherits FROM" para ser correcto), versus usar 2 palabras, que sea más humanamente legible, y bancarse eso a nivel técnico (después de todo el IDE te debería ayudar a no tener que tipear eso). Salvo que me esté perdiendo algún otro problema más fuerte conceptual de keywords multi palabra. Particularmente los verbos para expresar la relación con mixines son bastante chotos. "Mezcla" ? "se mezcla" ? "es mezclado" ? Dependen de la dirección de la expresión (léase quién es el sujeto, objeto etc) y suelen requerir 2 palabras.

La dirección actual es la de Scala, y además de hacer más dificil decidir una keyword tiene el problema del orden, como decía en el issue original. Eso me lleva a ... Experiencia de enseñar mixins con Scala:

En O3 de UNQ expliqué mixines por varios años, y SIEMPRE se daba la misma confusión al explicar cómo escribir y ppalmente LEER la sintaxis de mixins de Scala. Había 2 problemas para los cuales mi conclusión siempre fue "no es natural esta sintaxis" y es extremadamente confusa artificialmente (como tantas otras cosas de ruby, por ej). 1) El uso de "extends" para clases y mixines.

En Scala extends se usa para clases, como para mixins. Pero no siempre ! Depende de si mi texto declara una superclase o no ! Ej (A y B son clases, Mn son mixines)

class B extends A with M1 class B extends M1 class B extends M1 with M2

Para mí esto es superconfuso en un metamodelo que tiene clases y mixines ! O sea, entiendo y me parece seductora la idea de unificar conceptos, pero el camino ahí es borrar las clases, no esconderlas bajo una misma sintaxis. Y de última lo importante de fondo parecen ser las implicancias profundas de borrar las clases y trabajar sólo con mixins, más que la sintaxis. Mientras el lenguaje mantenga clases, es decir no plantee una forma radicalmente distinta de modelar comportamiento y trate a clases y a mixines de forma particular, para mí suena más claro diferenciar la forma de uso. Ok, en cuanto a la herencia podrían considerarse iguales, pero me suena a una unificación de conceptos parcial que termina siendo más académica que práctica y confundiendo al principiante.

El problema se puede resumir a que cuando uno arranca a explicar un concepto se espera tener esta forma: "los mixines son blah.. y los uso con esta sintaxis (una)". Si en cambio eso es "se usan igual que una superclase... si estoy declarando sólo un mixin, pero, si ya declaro superclase, se usan de esta otra forma, y ... si uso ambas tengo que volver a la forma de mixins y usar extends para la clase". Es medio una confusión. 2) El orden

Segundo problema que requería dedicarle vaaarios minutos sólo para explicar "cómo leerlo" porque no es intuitivo. Me parece que uno espera y desea poder ver en el código la linea de herencia, porque te evita un procesamiento mental recurrente de reordenar las cosas que estas viendo. En la sintaxis de Scala (copiada por wollok), está ese problema. Veo varios para hilar más fino. En dibujito se ve mejor. [image: image] https://user-images.githubusercontent.com/4428120/89797816-c7195d80-db01-11ea-81b4-5e3e3321c4ce.png (omito keywords)

Véase como hay que separar lo que se lee en 2 pasos para armar la herencia (pegar saltos al leer):

  • la clase abajo de todo
  • (no le doy vola a los mixins y...) lo primero a la derecha, la super clase, la mando arriba de todo
  • luego, lo que sigue, los mixins, los meto en el medio, reordenandolos de forma inversa.

Bastante confuso teniendo en cuenta que al final se arma una linea (exceptuemos herencia entre mixins).

Hay un 3er problema (además de tratar mentalmetne distinto a las clases, y luego reordenar los mixines) como bien dijeron sobre la duplicidad del concepto de la clase misma, porque aparece su nombre y su cuerpo. Para mí ahí no hay muchas opciones sin cambiar radicalmente la forma de declarar clases hacia algo que no me convence del todo,...

// <---------- lookup ----------

SuperClass mixed (with?) M1 and M2 and M3 derives class MiClase { .... métodos }

BTW esto se parece a mandarle mensajes a la super clase de smalltalk para declarar/crear una clase. Resuelve el orden en un 100%, pero bueno, es bastante controversial. Entonces en ppio yo me bajaría de la idea de unificar el cuerpo del método.

Vuelvo. Entiendo que todas las propuestas numeradas de NicoS mantienen ese tratamiento especial para las clases vs mixines. Y por eso la idea que más me gustaba (y acá mi opinión) era esta, que creo que es la que NicoS menciona como "variante transversal" al final.

[image: image] https://user-images.githubusercontent.com/4428120/89798642-d056fa00-db02-11ea-8ba6-f394398d2354.png

Me parece que es la que menos procesamiento mental requiere al lector. También uno puede pensar en las interacciones futuras, no pensando en que el que codea ya sabe exacto la linea que va a escribir. O bien que sufre refactors. Quizás arranco con

Clase inherits [from] SuperClase

// luego extraigo algo a un mixin toco expresando explícitamente cómo modifico la linea

Clase [mixes M1] inherits SuperClase

// y si agrego más, toco en el lugar que quiero afectar a la cadena DIRECTO: antes y después de M1 (las keywords medio que cagan)

Clase [mixes M0] mixes M1 [mixes M2] inherits SuperClase

Es un problema de sábana corta con los editores de textos tradicionales. Porque tener keywords más legibles como "and" "with" etc, maximizan la legibilidad pero al costo de luego tener que modificar cuando meto cambios. Idealmente un editor proyectivo/estructurado podría solucionar eso :P

Bueno, eso. Estoy completamente out de wollok hace varios años, pero vi esta discusión de refilón y quería apoyar la moción de cambio, porque como dije cada vez que expliqué este tema con Scala debía dar una "mecánica mental accesoria" para que los alumnos reformulen la linea de herencia.

Vuelvo al laburo :P Saludos !

PD: la mayoría de los lenguajes hacen cualquier con los mixins, porque nadie quiere romper las bases de las clases. Tal vez lo más interesante sería estudiar Self, que creo que es el único que lo hace bien y de hecho de donde nació la idea si no me equivoco.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/uqbar-project/wollok-language/issues/53#issuecomment-671428710, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACZRXGYMU3244LHJ2EIKAADSAAHYPANCNFSM4OYEUKUQ .

nscarcella commented 4 years ago

El vie., 14 ago. 2020 a las 0:52, Lucas Spigariol (notifications@github.com) escribió:

Poniendome en el lugar de un estudiante que conoce herencia y querer aprender mixins, (no tengo que hacer mucho esfuerzo ya que es mas o menos mi situacion...), coincido en primer lugar con el planteo de Alf

Sobre el orden de linearización y la pregunta que hizo Fer, no estaba mirando el método m, sino la clase Clase. Por eso prefería de izquierda a derecha: class Golondrina zaraza Volador zaraza Animal para mí significaba "sacá los métodos primero de Golondrina, luego de Volador y luego de Animal ". (pasa que yo los métodos no los veía "a la derecha", sino "abajo").

Cuando veo una herencia comun class Ave inherits Animal { } lo leo de izquierda a derecha. (Los mixins esperaria leerlos igual)

Sí, es una postura razonable. Supongo que todo se reduce a si uno considera a la clase más representada por su nombre o su cuerpo. Por eso dije que leerlo de izquierda a derecha es un poco más raro cuando la clase es anónima, porque no tenés nada representativo de ella a la izquierda. De todos modos, sí creo que es un detalle menor y no hace que la opción sea inválida. Si no fuera porque me da vértigo pensar en migrar todos los programas escritos con mixines invirtiendo el orden, esta también sería mi forma favorita.

Respecto de los terminos, prefiero los de una sola palabra, como quiere Nico. Retomando en parte lo que decia Javi que al inherits le faltaría el from, es aceptable usar un "mixes" sin with. Para enumarar los mixines, prefiero la coma antes que el and o repetir el with. Da mas idea de secuencia o serie, mientras que el and suena booleano. Tambien me cierra lo de repetir el mixes delante de cada mixin.

Yo creo que ponerle muchas fichas a la legibilidad es gastar polvora en chimangos. Nadie "lee" la cabecera de una clase, solamente aprendés a ignorar las palabras claves y mirar los nombrecitos. Si fuera una expresión que puede combinarse con otras donde las sutilezas de esa combinación llevaran a resultados distintos banco mucho el DSL, pero para esto me parece que no hace falta. Además me parece medio arbitrario... Porqué nos preocupamos por escribir la linearización en Haiku y después clavamos una llave y empezamos a gritar "const" y "method" como un indio? Eso y el lenguaje natural es ambiguo y traidor. Justamente hablando con Maiu ayer, me dijo que a ella no le gusta mucho el "and" como combinador de Mixines porque el "and" al que estamos acostumbrados tiene propiedades que la linearización no (por ej, es conmutativo). Mi sintáxis favorita es usar el churumbel que significa "es subtipo de" ( <: ) pero me vetaron los chirimbolos. Calculo que la coma entra también dentro de esa categoría.

En todo caso, al final del día no me importa mucho qué palabra se use (mientras no tenga espacios). Prefiero agarrar cualquier palabra que oferten y unificar las cinco notaciones pronto que colgarme a pelear la palabra para siempre.

Como dice Fer, a esta altura no cambiaría el inherits por otro termino.

Acuerdo con quitar el new y dejar el object en sus dos formas (var x = object inhertis/mixes... y object x inherits/mixes... )

hasta acá, es el asunto .....................................

Ahora, respecto de unificar terminos/conceptos, no tengo tan clara la diferencia como para opinar, pero me pregunto:

La diferencia entre trabajar con mixines o clases, está dada por la diferencia en sí de un mixin o una clase, o por el tipo de relación diferente que sugiere heredar o mixear?

El tema con plantear la diferencia entre trabajar con Mixins y Clases es entender que la combinación de Mixines es una generalización del modelo de herencia simple. O sea, la HS es un caso particular de la herencia con Mixines. Cuando un alumno aprende Mixines, no está enchufando un method lookup nuevo, está dándose cuenta que el method lookup no funcionaba como él creía. No es que el colectivo tenía otro ramal, es que vos siempre te quedabas dormido y no veías los lugares intermedios por donde pasaba. En términos de proveer comportamiento, la relación que un objeto tiene con su superclase es exactamente la misma que con sus mixines o, dicho en otros términos, para el objeto, todos sus supertipos son polimórficos. Entonces no existe realmente una diferencia entre "mixear" y "heredar" para lo que al lookup se refiere. Es más, los autores como Ducasse o Bracha hablan de "herencia" de mixines (por cierto, si están buscando algo para leer les recomiendo mucho los primeros capítulos de la tesis de Bracha http://www.bracha.org/jigsaw.pdf, donde se explaya sobre todo esto).

Con lo cual la diferencia entre Clase y Mixin es la semántica y restricciones que vos le asignes a cada uno en el lenguaje. Cosas como que un objeto puede tener una única superclase, o que no podés instanciar un mixin, que son ajenas al proceso de lookup.

*Es cierto que "poder tener una sola" es parte de la relación entre una clase y su superclase, pero la pregunta es si vale la pena que la sintaxis haga hincapié en esto o no. Yo tengo mis dudas... Sobre todo porque no p*odés detectar a nivel sintáctico si tu relación es correcta o no. "class C inherits A mixed with B" sólo está bien si A es una clase y B es un mixin. Si A es un mixin y B es una clase ese código está mal y no podés forzar esa precedencia escribiendo: "class C mixed with B inherits A" porque el orden entre mixines y clases está predeterminado en el lenguaje. De la misma manera, si los dos son clases está mal y no hay forma de escribirlo para que funcione.

*Con lo cual, al usar palabras diferentes, n*o estás ni eligiendo el orden entre clases y mixines ni tampoco qué "relación" usar: La clase va a ser tu superclase y el mixín va a estar entre tus mixines. Siempre.

En definitiva la palabra clave que uses no es más que un indicador de que vos sabés que ese nombre que escribiste corresponde a una clase o a un mixin, y esa validación es tan valiosa como creamos que es... El compilador puede hacer todos los chequeos que hace sin esas palabras (chequear que no tengas más de una superclase, el orden de inclusión, etc) y avisarte de la misma manera.

Sí puedo decir por experiencia trabajando con lenguajes con sintaxis similar que esto hace que refactorizar una clase para convertirla en mixin (algo más bien común) se vuelve un pijazo, porque tenés que ir por todos lados cambiando el inherits por el mixed.

En otras palabras, que es lo que tiene mas sentido:

¿tener solo inherits, pero que dependiendo que sea de un mixin o una clase signifique cosas distintas? (esta seria la opcion 1 de nico?)

¿o pensar que existen las clases, que pueden declararse o no como

abstractas, (y no los mixines) manteniendo las diferencias entre mixear y heredar ?

Esto último no lo entendí.

por otra parte, imaginando la existencia de una herencia multiple, si tuvieramos class A inherits B inherits C ¿que tendria de diferente con class A mixes B mixes C ?

  • No creo que exista ninguna diferencia para el usuario de un lenguaje entre tener Mixines instanciables o Herencia Multiple donde los conflictos se resuelven por linearización (como Pyton). *Ahora mismo en Wollok las clases no ofrecen nada que no puedas hacer con mixines, porque siempre podés crear objects anónimos linearizando mixines (efectivamente "instanciando" mixines). Un poco por eso creo que la herencia múltiple (o roles o como quieran decirle) es superador de cualquier modelo de herencia simple+mixines.

El lun., 10 de ago. de 2020 a la(s) 12:36, Javier Fernandes ( notifications@github.com) escribió:

Buenas. Aporto 3 cosas: algo de historia, algo de experiencia y una opinión. Historia (se puede skipear)

Las inconsistencias de sintaxis no son producto de un descuido sino mas bien de limitaciones por ambigüedad (si no me equivoco, ya pasaron fácil como 3 o 4 años desde que implementé los mixins) de la gramática de XText. O bueno, si quieren una limitación mía para desambigüar eso en la gramática. Obviamente no recuerdo los detalles.

El tener una keyword compuesta fue más bien una lucha interna de "1 única keyword pero que produzca un texto pseudo inglés-indio confuso" como pasa hoy con "inherits" que es justamente por lo que nunca me gustó (técnicamente debería ser "inherits FROM" para ser correcto), versus usar 2 palabras, que sea más humanamente legible, y bancarse eso a nivel técnico (después de todo el IDE te debería ayudar a no tener que tipear eso). Salvo que me esté perdiendo algún otro problema más fuerte conceptual de keywords multi palabra. Particularmente los verbos para expresar la relación con mixines son bastante chotos. "Mezcla" ? "se mezcla" ? "es mezclado" ? Dependen de la dirección de la expresión (léase quién es el sujeto, objeto etc) y suelen requerir 2 palabras.

La dirección actual es la de Scala, y además de hacer más dificil decidir una keyword tiene el problema del orden, como decía en el issue original. Eso me lleva a ... Experiencia de enseñar mixins con Scala:

En O3 de UNQ expliqué mixines por varios años, y SIEMPRE se daba la misma confusión al explicar cómo escribir y ppalmente LEER la sintaxis de mixins de Scala. Había 2 problemas para los cuales mi conclusión siempre fue "no es natural esta sintaxis" y es extremadamente confusa artificialmente (como tantas otras cosas de ruby, por ej). 1) El uso de "extends" para clases y mixines.

En Scala extends se usa para clases, como para mixins. Pero no siempre ! Depende de si mi texto declara una superclase o no ! Ej (A y B son clases, Mn son mixines)

class B extends A with M1 class B extends M1 class B extends M1 with M2

Para mí esto es superconfuso en un metamodelo que tiene clases y mixines ! O sea, entiendo y me parece seductora la idea de unificar conceptos, pero el camino ahí es borrar las clases, no esconderlas bajo una misma sintaxis. Y de última lo importante de fondo parecen ser las implicancias profundas de borrar las clases y trabajar sólo con mixins, más que la sintaxis. Mientras el lenguaje mantenga clases, es decir no plantee una forma radicalmente distinta de modelar comportamiento y trate a clases y a mixines de forma particular, para mí suena más claro diferenciar la forma de uso. Ok, en cuanto a la herencia podrían considerarse iguales, pero me suena a una unificación de conceptos parcial que termina siendo más académica que práctica y confundiendo al principiante.

El problema se puede resumir a que cuando uno arranca a explicar un concepto se espera tener esta forma: "los mixines son blah.. y los uso con esta sintaxis (una)". Si en cambio eso es "se usan igual que una superclase... si estoy declarando sólo un mixin, pero, si ya declaro superclase, se usan de esta otra forma, y ... si uso ambas tengo que volver a la forma de mixins y usar extends para la clase". Es medio una confusión. 2) El orden

Segundo problema que requería dedicarle vaaarios minutos sólo para explicar "cómo leerlo" porque no es intuitivo. Me parece que uno espera y desea poder ver en el código la linea de herencia, porque te evita un procesamiento mental recurrente de reordenar las cosas que estas viendo. En la sintaxis de Scala (copiada por wollok), está ese problema. Veo varios para hilar más fino. En dibujito se ve mejor. [image: image] < https://user-images.githubusercontent.com/4428120/89797816-c7195d80-db01-11ea-81b4-5e3e3321c4ce.png

(omito keywords)

Véase como hay que separar lo que se lee en 2 pasos para armar la herencia (pegar saltos al leer):

  • la clase abajo de todo
  • (no le doy vola a los mixins y...) lo primero a la derecha, la super clase, la mando arriba de todo
  • luego, lo que sigue, los mixins, los meto en el medio, reordenandolos de forma inversa.

Bastante confuso teniendo en cuenta que al final se arma una linea (exceptuemos herencia entre mixins).

Hay un 3er problema (además de tratar mentalmetne distinto a las clases, y luego reordenar los mixines) como bien dijeron sobre la duplicidad del concepto de la clase misma, porque aparece su nombre y su cuerpo. Para mí ahí no hay muchas opciones sin cambiar radicalmente la forma de declarar clases hacia algo que no me convence del todo,...

// <---------- lookup ----------

SuperClass mixed (with?) M1 and M2 and M3 derives class MiClase { .... métodos }

BTW esto se parece a mandarle mensajes a la super clase de smalltalk para declarar/crear una clase. Resuelve el orden en un 100%, pero bueno, es bastante controversial. Entonces en ppio yo me bajaría de la idea de unificar el cuerpo del método.

Vuelvo. Entiendo que todas las propuestas numeradas de NicoS mantienen ese tratamiento especial para las clases vs mixines. Y por eso la idea que más me gustaba (y acá mi opinión) era esta, que creo que es la que NicoS menciona como "variante transversal" al final.

[image: image] < https://user-images.githubusercontent.com/4428120/89798642-d056fa00-db02-11ea-8ba6-f394398d2354.png

Me parece que es la que menos procesamiento mental requiere al lector. También uno puede pensar en las interacciones futuras, no pensando en que el que codea ya sabe exacto la linea que va a escribir. O bien que sufre refactors. Quizás arranco con

Clase inherits [from] SuperClase

// luego extraigo algo a un mixin toco expresando explícitamente cómo modifico la linea

Clase [mixes M1] inherits SuperClase

// y si agrego más, toco en el lugar que quiero afectar a la cadena DIRECTO: antes y después de M1 (las keywords medio que cagan)

Clase [mixes M0] mixes M1 [mixes M2] inherits SuperClase

Es un problema de sábana corta con los editores de textos tradicionales. Porque tener keywords más legibles como "and" "with" etc, maximizan la legibilidad pero al costo de luego tener que modificar cuando meto cambios. Idealmente un editor proyectivo/estructurado podría solucionar eso :P

Bueno, eso. Estoy completamente out de wollok hace varios años, pero vi esta discusión de refilón y quería apoyar la moción de cambio, porque como dije cada vez que expliqué este tema con Scala debía dar una "mecánica mental accesoria" para que los alumnos reformulen la linea de herencia.

Vuelvo al laburo :P Saludos !

PD: la mayoría de los lenguajes hacen cualquier con los mixins, porque nadie quiere romper las bases de las clases. Tal vez lo más interesante sería estudiar Self, que creo que es el único que lo hace bien y de hecho de donde nació la idea si no me equivoco.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub < https://github.com/uqbar-project/wollok-language/issues/53#issuecomment-671428710 , or unsubscribe < https://github.com/notifications/unsubscribe-auth/ACZRXGYMU3244LHJ2EIKAADSAAHYPANCNFSM4OYEUKUQ

.

— 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/53#issuecomment-673868465, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPE223NOASSX7G3UDH7XDSASYIBANCNFSM4OYEUKUQ .

asanzo commented 4 years ago

Con esto último que dijo Nico estoy un poco menos convencido de querer dos palabras distintas (inherits y mixes).

Ya que sea class o mixin en la definición de la cosa (class Clasy, mixin Mixy) me parece suficiente. Con eso ya puedo contar las diferencias de diseño y de modelado.

Y que sea todo inherits y a la verga (class A inherits Clasy inherits Mixy o la variante que quede). Sobre el orden ya me explayé y sobre los chirimbolos no recuerdo si lo hice pero a priori no puedo argumentar mucho a favor o en contra.

fdodino commented 4 years ago

Con esto último que dijo Nico estoy un poco menos convencido de querer dos palabras distintas (inherits y mixes).

Me sumo a que NicoS puede llegar a convencernos más que fácilmente a Alf y a mí de usar inherits para ambas cosas. Es decir, no me jode porque yo veo al usuario del mixin como un nivel más avanzado que el de la herencia simple, u otro estadío, y ahí puede incorporar la idea del inherits. Tendría que ver ahora la propuesta nuevamente... porque incluso estaría dispuesto a permitir una coma... tengo que sentarme a ordenar las ideas para no tirar fruta.

nscarcella commented 4 years ago

Igual, ojo, yo no estoy especialmente a favor de ninguna de las opciones, pero está bueno hilar fino sobre estos temas porque rara vez tenemos la oportunidad de discutirlo entre todos y es una buena oportunidad para unificar criterios.

Lo que saco más o menos en limpio de lo hablado dentro y fuera del thread es que:

a) Hay varios que encuentran la precedencia de izquierda a derecha más natural que de derecha a izquierda. b) En general "extends ... with" parece gustar más que "inherits ... and" pero el costo de migrar todo es demasiado alto para que valga la pena. c) Nadie parece tener problemas con eliminar el "new" de clases anónimas (algunos ni sabían que se podía) dejando sólo object {}. d) No estamos listos, como sociedad, para escribir: https://en.wikipedia.org/wiki/Subtyping class C <: M1 <: M2 <: D https://en.wikipedia.org/wiki/Subtyping :P

Eso más o menos nos va perfilando para alguna de las siguientes dos variantes:

class C1 inherits M1 and M2 and C2

class C1 mixes M1 and M2 inherits C2

Si algo rescato más de la primera variante que de la segunda es que permite una eventual transición a tener roles (o herencia múltiple linearizada, o como quieran decirle) más suave que la segunda. Lo único que habría que hacer permitirte intercalar otras clases además de mixines:

class C1 inherits M1 and C2 and M2 and C3

No sé. Lo dejo a sus criterios.

Porfa, si alguien todavía no opinó estaría bueno tener el feedback de todos (especialmente de los que ya dieron clases con mixines).

N.

El sáb., 15 ago. 2020 a las 13:38, Fernando Dodino (< notifications@github.com>) escribió:

Con esto último que dijo Nico estoy un poco menos convencido de querer dos palabras distintas (inherits y mixes). Me sumo a que NicoS puede llegar a convencernos más que fácilmente a Alf y a mí de usar inherits para ambas cosas. Es decir, no me jode porque yo veo al usuario del mixin como un nivel más avanzado que el de la herencia simple, u otro estadío, y ahí puede incorporar la idea del inherits. Tendría que ver ahora la propuesta nuevamente... porque incluso estaría dispuesto a permitir una coma... tengo que sentarme a ordenar las ideas para no tirar fruta.

— 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/53#issuecomment-674420815, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFPE27BSHFEDJZQBZA5263SA22WZANCNFSM4OYEUKUQ .

fdodino commented 4 years ago

Versión final final final posta posta:

Todas las clases pueden tener parámetros nombrados, pasándole los atributos que sean necesarios

// CLASES
// Con todo
class C1 inherits M1 and M2 and C2 { method m() {...}  }
// Sólo superclase
class C1 inherits C2(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
class Clase inherits M1(arg4 = p4) { method m() {...}  }
// Sin nada
class Clase { method m() {...}  }

// MIXINS
// Con mixins
mixin Mixin inherits M1(arg3 = p3) and M2(arg4 = p4) { method m() {...}  }
// Sin nada
mixin Mixin { method m() {...}  }

// SINGLETONS NOMBRADOS
// Con todo
object singleton inherits M1 and SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo superclase
object singleton inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object singleton inherits M1(arg3 = p3) and M2(arg4 = p4) { method m() {...}  }
// Sin nada
object singleton { method m() {...}  }

// SINGLETONS ANÓNIMOS
// Con todo
object inherits M1 and M2 and SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo superclase
object inherits SuperClass(arg1 = p1, arg2 = p2) { method m() {...}  }
// Sólo mixins
object inherits M1(arg3 = p3) and M2(arg4 = p4) { method m() {...}  }
// Sin nada
object { method m() {...}  }

// NEW DE CLASES ANÓNIMAS
// Se descarta en favor del singleton
nscarcella commented 3 years ago

Buenas, como ya estamos mirando esto para TS, por las dudas armé un doc parecido al que armamos para la especificación de la instanciación. Lo pueden encontrár acá. Creo haber compartido y linkeado en todos los lugares pertinentes, pero cualquier cosa avisen.

PalumboN commented 3 years ago

@fdodino @nscarcella esto ya está implementado, no?

fdodino commented 3 years ago

Sí para Wollok Xtext, señor!

nscarcella commented 3 years ago

Hijo de puta copiaste y pegaste el arroba en todos los tickets abiertos, no?

fdodino commented 3 years ago

Jajajaj, estallé en el medio del final de PDP

PalumboN commented 3 years ago

Jajajaj solo en los que no estaba seguro :innocent: