viernes, mayo 04, 2007

¿Por qué triunfa un lenguaje?

Es evidente que un lenguaje no siempre triunfa exclusivamente por sus méritos propios. De lo contrario, ¿cómo explicaríamos el larguísimo reinado de C++ y el injusto olvido de Eiffel?
En ocasiones, sin embargo, las causas del triunfo pueden ser sorprendentes, y puede que no hayan sido previstas por su autor. Lo digo porque acabo de recordar algo muy importante que influyó en mi decisión de usar Delphi como herramienta principal de programación... a pesar de conocer bien C++ y del estado más avanzado de este lenguaje y sus implementaciones por aquel entonces. No olvide que, a pesar de los méritos innegables de los genéricos de .NET, C++ tiene templates desde tiempo inmemoriales, igual que Eiffel (y no digamos ya Ada).
Me voy a callar esta causa (hay muchas más, qué duda cabe) un tiempo. Si quiere contar la suya en los comentarios, las iré añadiendo a este post (para ser más concisos, utilice negritas, si quiere, para destacar la parte que quiere que copie). Y luego diré la mía, si nadie la menciona antes...

Etiquetas: , ,

29 Comments:

Anonymous Anónimo said...

Pues por pura casualidad... cayo en mis manos el Turbo Pascal antes que el Turbo C, me gusto el lenguaje lo fui aprendiendo y de ahí pase al Delphi... y encantado por su potencia, elegancia y no se cuanta cosas más.

viernes, mayo 04, 2007 10:09:00 p. m.  
Anonymous Anónimo said...

Por aquel entonces, tenía una aplicación en Visual Basic que tenía que crear dinámicamente controles en pantalla según el número de registros de una tabla bastante sensible al tamaño (el tamaño de aquel entonces). Unos 1000 registros tardaban en procesarse 54 segundos en mi máquina. Cuando pasé a Delphi, conseguí hacer lo mismo en menos de 2 segundos. Además el compilador volaba, mientras que el de Visual Basic se arrastraba.

sábado, mayo 05, 2007 8:37:00 a. m.  
Anonymous Anónimo said...

Por cierto, el compilador de C# también es muy lento. Cuando el proyecto empieza a ser un poco grande, cargarlo es eterno. Desde que abres una pantalla con bastantes controles hasta que puedes empezar a hacer algo, se eterniza, por no hablar de la cantidad de veces que sale un error en el diseñador y te miente con que tal o cual propiedad no se puede enlazar y cosas así. Otras veces se cierra el Visual Studio sin más. Los tiempos de compilación también son tremendos.

sábado, mayo 05, 2007 8:39:00 a. m.  
Anonymous Anónimo said...

Por elegancia, por potencia, por rapidez. Desde que cogi el delphi por primera vez me gustó cosa que no puedo decir del c# y del visual studio 2005.

sábado, mayo 05, 2007 11:48:00 a. m.  
Anonymous Anónimo said...

Lo mio fue mas ganduleria o pereza, una primera fase con Turbo-Pascal y Turbo-C, el posterior decubrimento del dBase y su facilidad para utilizar bases de datos relacionales me llevo inevitablemente al Clipper, que en aquella epoca era rey en MS-DOS de las aplicaciones de getion domesticas del tipo 'la ferreteria de mi primo'.
Con el advenimiento del windows me dedique a buscar entornos donde programar las mismas aplicaciones y de la misma manera que en MS-DOS,
y tras pasar por Visual Objects, Acces, Paradox, Delphi, etc. Acabe con el unico lenguage y entorno de desarrollo que me daba la productividad perdida de mi epoca Clipper, ese lenguage era 'Clarion'.
Lo mio como veis no es una custion de elegancia o sintaxis, tampoco de eficiencia o rendimento, es una simple cuestion practica, la pela es la pela, y una aplicacion tipica de gestion se desarrollaba en Clarion en la mitad de tiempo que en los otros lenguages.
Por desgracia aunque el Clarion sigue existiendo su evolucion es lentisima y dificilisimo (internet aparte) encontrar a alguien que lo utilize, de hecho nunca he mirado a los ojos a un programador en Clarion a parte de mismo cuando me miro en un espejo, a veces dudo de su existencia, y al mismo tiempo de la mia propia.
Al respecto de todo esto os agradecria una respuesta sincera a una pregunta que me corroe por dentro.
¿ Es cierto que cuando llevas muuuchos años años programando con lenguages procedurales el daño en el cerebro ya es irreversible, y es imposible aprender a programar con lenguages OOP con la misma productividad y eficiencia que ya tienes en tu viejo estilo. ?
Estoy intentando trabajar con C# y la verdad el cambio es dificil,
¿Hay esperanza?.
Gracias.

sábado, mayo 05, 2007 1:57:00 p. m.  
Anonymous Anónimo said...

Mis causas por las que ahora elijo Delphi a pesar de contar con la plataforma de Borland Studio 2006 con C++, Delphi y C# en un mismo paquete, son 3 y relativamente sencillas:
1. C# aun no lo tengo tan "toreado" como para usarlo en un lenguaje visual y menos empezando con una plataforma de Borland xD . Tiene buena pinta, todo se andará...
2. La cantidad de documentación e información que hay sobre Delphi en la red, la cual no se amplía en absoluto a C++ Builder en la mayoría de los casos.
3. Y diría que esta es la más importante en mi caso. ¿Alguno de ustedes ha comparado los fuentes pregenerados que saca Borland C++ Builder, cuando por ejemplo, creamos un nuevo form? ¿No resultan algo... sucios? Es decir, con todas esas directivas *forzadas* por Borland y esos separadores a base de comentarios...

En fin, no quiero que se me malinterprete. Llevo mucho C y C++ mascado ya, aunque más a pelo que otra cosa, o sobre plataformas Unix, y sinceramente me gusta más que Pascal o ObjectPascal. Pero Delphi fue orientado desde el principio a lo que es, es decir, un lenguaje pensado para programación visual y a desarrollo rápido de aplicaciones gráficas (un híbrido, como lo llaman algunos), y creo que por mi parte, es por eso por lo que se lleva la palma en este caso.

Un saludo y felicidades por el blog.

lunes, mayo 07, 2007 2:52:00 a. m.  
Anonymous Anónimo said...

Yo venía de C++ para DOS y tuve que meterme en Delphi (Delphi2 en aquel entonces, año 1996) obligado por el puesto de trabajo. Fue un grato descubrimiento por los siguientes motivos (hablaré en pasado):

1) Ejecutable autosuficiente: Delphi producía un ejecutable final que no dependía de DLLs (si exceptuamos, claro está, las propias del sistema operativo), al contrario que ocurría con VB.

2) RTTI: en mi caso, fue un valioso recurso para poder modificar el texto de todos los controles de un formulario (por ejemplo, cuando el usuario elegía cambiar de idioma) con independencia del diseño del formulario.

3) Comparación con VB & C++: al contrario que VB, Delphi era un lenguaje real OO y comparando con C++, me parecía más legible, más simple (no había herencia múltiple, ni aritmética de punteros, ...) y se prestaba a menos errores ortográficos (por ejemplo, asignaciones en comparaciones. ¿A quién no le ha pasado en C querer escribir una comparación (if (a==b)) para equivocarse y escribir también una asignación (if (a=b))? A mí esto me costaba días detectarlo y mala sangre).

lunes, mayo 07, 2007 8:45:00 p. m.  
Blogger Alfredo Novoa said...

Hay muchos lenguajes mejores que C#, y no digamos ya que Delphi, pero el lenguaje no suele ser lo más importante en un entorno de programación.

La razón fundamental por la que me pasé a C# fue por que a pesar de que ADO .NET es una completa castaña es relativamente fácil de sustituir. En cambio programar DataSets para Delphi es un infierno. Además de eso Borland era un barco que se veía claramente que se iba a pique desde hacía tiempo. Para competir con Microsoft tienes que tener productos mucho mejores, y Borland hace mucho que no los tiene.

martes, mayo 08, 2007 12:30:00 p. m.  
Blogger Ian Marteens said...

Yo me pasé, por supuesto, por el buen soporte "visual"... pero lo racionalicé con el soporte del lenguaje para los "métodos dinámicos de mensajes", que vienen de Turbo Pascal para Windows, si no recuerdo mal. Es un truco adhoc, pero para mí significó, en aquel momento, que en Borland estaban dispuestos a hacer lo necesario para que el lenguaje evolucionase hacia donde hiciera falta. Claro, después de Delphi 3 llegó el marasmo. Por supuesto que siempre pensé que Delphi estaba incompleto como lenguaje, pero confiaba en que se resolviese con el tiempo.

Si os parece una tontería lo de los métodos message, recordad que fue el mismísimo Charles Petzold quien dijo que nunca se podría programar Windows desde Pascal... y en cierto sentido tenía razón. Turbo Pascal para Windows, y ya no digo Delphi 1, ya no eran "Pascal", hablando con propiedad.

Ahora, sin embargo, a nadie le sorprende ya que no haya un truco de este tipo (o un "message cracker") en los nuevos lenguajes. Puede que el cambio sea mérito de Java (alguno tenía que tener, el pobrecillo).

ni aritmética de punteros

Mikel, :) ¿quién dijo que no?

Hay muchos lenguajes mejores que C#, y no digamos ya que Delphi

Alfredo, je, je, ¿qué te parecen las mónadas?

Un saludo y felicidades por el blog.

Muchas gracias, Inti. Y un saludo a todos.

miércoles, mayo 09, 2007 12:01:00 a. m.  
Blogger Alfredo Novoa said...

Alfredo, je, je, ¿qué te parecen las mónadas?

Eran pajas mentales de un señor que vivió en el siglo XVII, y no se que tienen que ver con los lenguajes de programación.

miércoles, mayo 09, 2007 12:22:00 a. m.  
Blogger Alfredo Novoa said...

Alfredo, je, je, ¿qué te parecen las mónadas?

Ya caigo, te refieres a Haskell.

Pues me parecen un lío de cojones, siempre me he quedado antes.

miércoles, mayo 09, 2007 12:42:00 a. m.  
Blogger Ian Marteens said...

:) Menos mal que miré antes de publicar el comentario. Dejo sólo lo relevante:

[...]

Ah, y tienen alguna relación con LINQ, según Erick Meijer:

Erick Meijer

¿Sabías que Peyton-Jones, Cardelli, Meijer y pandilla se habían mudado en masa a Microsoft Research? Ah, y el gran R.C.A. "Tony" Hoare, aunque creo que Hoare está un poco "nominalmente".

Por cierto, sobre las mónadas del otro señor: libro recomendable y recomendado, The Courtier and the Heretic: Leibniz, Spinoza, and the Fate of God in the Modern World. Tendría que escribir una reseña...

miércoles, mayo 09, 2007 12:55:00 a. m.  
Blogger Alfredo Novoa said...

A mi la programación funcional no me parece muy interesante para trabajar con bases de datos, que es a lo que me dedico. Lo que me interesa es precisamente trabajar con el estado de una variable que es la base de datos.

Estoy más interesado en la programación declarativa-imperativa y la programación lógica.

miércoles, mayo 09, 2007 12:55:00 a. m.  
Blogger Ian Marteens said...

programación lógica

Yo también. Pero una vez superado el problema de no guarrear la PF con efectos paralelos, puede ser una buena opción.

Por cierto, tengo un par de ideíllas sobre Aspect Oriented Programming. Tengo que redactarlo para hacerme entender, pero cuando lo tenga listo, me gustaría oir tu opinión. A grandes rasgos:

1- Mi digestión personal de la AOP me hace ver estas ideas como técnicas complementarias que miran y manipulan directamente el código fuente. Un aspect weaver sería simplemente un preprocesador monstruoso que sería capaz de inyectar código en sitios extraños... en los que no tendría sentido según la OOP.

2- Sin embargo, hay mucho de razón en la idea: ahí está COM+, seguridad, transacciones declarativas y esas cosas. Y no estamos hablando de tratamiento de excepciones, porque mucho antes de existir la AOP ya se había ideado una solución ad hoc.

3- Por desgracia, lo que veo implementado en AspectJ y demás es MUY peligroso. Se puede cargar la semántica de cualquier programa, porque no tiene en cuenta contratos, aserciones ni nada.

Aquí se podría abandonar la idea, claro, pero...

4- Busquemos una forma de limitar su aplicación a casos "con sentido". En vez de permitir inyección en todos los prólogos y epílogos de métodos, ¿por qué no asociar los puntos de inyección al acceso o modificación de recursos?

5- "Ya, eso es lo que hacen las propiedades". Sí... pero sólo si cada aspecto se tejiese por separado. ¿Y si se exige la consolidación del código generado? Por ejemplo, para cada método que manipule el estado de CurrentPosition en un editor, se genera un prólogo y un epílogo desde el que se dispara ¡una sola vez! un evento SelectionChanged. Eso no se puede lograr sólo a golpe de propiedades... y es muy tedioso, peligroso y confuso hacerlo a mano. Aquí, sin embargo, estaríamos aprovechando gran parte de la voluminosa información que reúne un compilador y que después simplemente se tira en provecho nuestro.

6- Muy someramente, una primera idea básica consistiría en definir "data triggers" asociados a recursos (¿campos?, ¿o también métodos, propiedades...?). El código generado se especificaría en una sección independiente de la clase, y estaría completamente aislado de los recursos de ésta... con la excepción, por supuesto, del recurso "vigilado". Esto reduciría las dependencias y disminuiría los riesgos de cargarse el sistema hasta niveles razonables.

7- Importante: la "vigilancia" no ocurre en tiempo de ejecución, ¡sino de compilación!

Creo que con esto se podría conseguir, y de manera segura, uno de los efectos interesantes y populares de la AOP. ¿Sería suficiente?

Observa también que esta técnica podría servir de base a la implementación de la verificación dinámica de los invariantes de clase. ¡Los puntos clásicos de esta verificación son los puntos característicos para la inyección de código de la AOP!

Como ves, es todavía una idea muy verde y borrosa, pero es relativamente fácil de implementar, la formulación, con un poco de cuidado y buen gusto, puede ser elegante, y es el tipo de pequeño avance evolutivo "posibilista" y útil que puede sufrir un lenguaje imperativo sin perder su identidad... aunque ganando personalidad.

miércoles, mayo 09, 2007 1:26:00 a. m.  
Blogger Alfredo Novoa said...

¿Sabías que Peyton-Jones, Cardelli, Meijer y pandilla se habían mudado en masa a Microsoft Research?

Si, lo había visto hace tiempo, pero hay bastante material nuevo desde la última vez que entré.

He leido más sobre las mónadas y me siguen pareciendo un lío para hacer algo que es trivial usando variables. Hay una mónada que se parece bastante a los tipos anulables y eso es una cosa bastante fea.

1- Mi digestión personal de la AOP me hace ver estas ideas como técnicas complementarias que miran y manipulan directamente el código fuente.

Si, una cosa bastante modesta. Hay mucho humo en la AOP.

Un aspect weaver sería simplemente un preprocesador monstruoso que sería capaz de inyectar código en sitios extraños

De acuerdo.

2- Sin embargo, hay mucho de razón en la idea: ahí está COM+, seguridad, transacciones declarativas y esas cosas.


A mi me parece una ñapa usar la AOP para estas cosas. Sería mejor aumentar la potencia expresiva de los lenguajes. Por ejemplo se podrían incluir las transacciones como ciudadanos de primera clase y también nueva sintaxis para asignaciones múltiples como:

a := a + b,
c := c - b;

La coma no es una errata, es la forma de indicar una asignación múltiple ("thread safe" y todo eso).

Mi lenguaje tiene las dos cosas O:-)

4- Busquemos una forma de limitar su aplicación a casos "con sentido". En vez de permitir inyección en todos los prólogos y epílogos de métodos,

Yo para hacer esto prefiero un editor potente. Es decir inyectar el código en los fuentes y no en los ejecutables. Tampoco es una cosa que haya que hacer muy a menudo.

Por ejemplo, para cada método que manipule el estado de CurrentPosition en un editor, se genera un prólogo y un epílogo desde el que se dispara ¡una sola vez! un evento SelectionChanged. Eso no se puede lograr sólo a golpe de propiedades... y es muy tedioso, peligroso y confuso hacerlo a mano.

Yo esto lo haría usando algo parecido a la introspección. Que cada método o propiedad pudiese preguntar cosas sobre quien le está llamando. Así solo habría que tocar en un punto.

6- Muy someramente, una primera idea básica consistiría en definir "data triggers" asociados a recursos (¿campos?, ¿o también métodos, propiedades...?). El código generado se especificaría en una sección independiente de la clase

Bueno, ya sabes que yo quiero tener TODO el código separado de la definición del tipo O:-), pero la idea me parece interesante cuando no tienes acceso al código de la clase, sino con mejorar la introspección sería suficiente.

Hay un principio de diseño de lenguajes de programación que se llama el principio del diseño cauteloso, que dice que antes de añadir nuevas características a un lenguaje hay que pensar, bien si vale la pena.

Con esto no quiero decir que lo que dices no vale la pena, sino que si no lo tienes muy claro mejor no añadirlo O:-)

miércoles, mayo 09, 2007 4:43:00 a. m.  
Blogger Ian Marteens said...

He leido más sobre las mónadas y me siguen pareciendo un lío para hacer algo que es trivial usando variables.

Aunque "variable" no es sinónimo de "side-effect", o usas mónadas, o usas continuaciones o "streams... o metes side-effects en el lenguaje, como en ML, y destrozas la facilidad de "razonar" sobre sus propiedades.

Las he traído a colación porque ilustran un problema: el pedagógico. Aunque la explicación de por qué funciona eche mano de la teoría de categorías, el recurso en sí no se sale del cálculo lambda. Si no lo he pillado mal, es simplemente un patrón de programación... con un nombre horrible, y con un puñado de matemáticos revoloteando excitados a su alrededor mientras intentan que la peña lo comprenda. Me recuerda la furia que causó en su momento XSLT: todo el mundo quería escribir su próxima aplicación Web con XSLT... aunque luego la empresa contratase un becario para su mantenimiento y el becario no entendiese ni le interesase el álgebra.

miércoles, mayo 09, 2007 2:26:00 p. m.  
Blogger Ian Marteens said...

Es decir inyectar el código en los fuentes y no en los ejecutables.

Yo también... pero en tiempo de compilación, no de edición.

Tampoco es una cosa que haya que hacer muy a menudo.

Por el contrario: cada vez que añadieses un método, como mínimo. Y si intentases hacerlo bien, es decir, incluir el código sólo donde se accede al recurso, ahí mismo empezarían los errores. Cada vez que modificases un método, tendrías que volver a preguntarte si necesitas el prólogo y el epílogo.

Y está el problema del mantenimiento del propio código insertado. Para empezar, tendrías que reducirlo a su mínima expresión: un procedimiento o una función, como máximo, e incluso en el caso de una función, ya habría problemas, porque ¿dónde dejarías el resultado de la función? ¿Una variable local? ¿Por cada método retocado? El encapsulamiento a hacer puñetas... y se supone que eso es lo que la AOP quiere salvar.

Por supuesto, un "editor" podría hacerlo... siempre que el editor te diese acceso a la información de Intellisense y programases un pedazo de macro como para que te den un Turing (¡oye!, no está mal la frase como insulto: "anda y que te den un Turing", además, la frase es "autológica", como los adjetivos, respecto a una de sus partes).

miércoles, mayo 09, 2007 2:53:00 p. m.  
Blogger Alfredo Novoa said...

Aunque "variable" no es sinónimo de "side-effect", o usas mónadas, o usas continuaciones o "streams... o metes side-effects en el lenguaje, como en ML

Pero con las mónadas tienes "side effects".

, y destrozas la facilidad de "razonar" sobre sus propiedades.

Yo creo que marcando con un atributo las funciones que no son referencialmente transparentes ya no destrozas nada.

Por ejemplo esas funciones tienen que estar prohibidas en la declaración de restricciones. Si usas mónadas estás en las mismas.

Por el contrario: cada vez que añadieses un método, como mínimo.

Me refiero a que no me ha pasado nunca el tener que añadir un prólogo y un epílogo iguales a un montón de procedimientos.

La AOP me parece que son un puñado de trucos ad-hoc que nunca he echado en falta, e invocan de una forma bastante inapropiada el principio de "separation of concerns" de Dijkstra. En eso la programación lógica y el Modelo Relacional está años luz por delante.

También he visto muchos ejemplos de AOP para implementar lógica de negocio en las aplicaciones lo cuál es un disparate.

Tu ejemplo de la CurrentPosition no es realista. El efecto deseado se consigue con una simple variable booleana. El típico ejemplo de los "log" tampoco es realista.

¿Conoces esto?:

CodeGenerationIsaDesignSmell

miércoles, mayo 09, 2007 4:12:00 p. m.  
Blogger Ian Marteens said...

Tu ejemplo de la CurrentPosition no es realista. El efecto deseado se consigue con una simple variable booleana.

¿! ¿Cómo? A lo mejor es ése mi problema: no lo veo. El ejemplo es mi propio editor de código: podría, a golpe de disciplina, haber evitado el uso de currentPosition, el campo, y limitarme a CurrentPosition, la propiedad (simplificando un poco). Pero no quería que se disparase el evento cada vez que asignase cualquier tontería temporal en la variable.

Objeciones:

1- Podría haber utilizado (nuevamente a golpe de mucha disciplina) un protocolo en el que la posición se lee al principio de cada método en una local, que se actualiza y sólo se reasigna a la propiedad al terminar.

Grandísimo problema: se llama "componibilidad" (vale, o algo parecido). Si creo el método A a partir de los métodos preexistentes B y C, ya tengo disparos repetidos. Oh, claro, se puede arreglar con un "contador de nivel" que se incremente en cada prólogo de método y se decremente en el epílogo. El disparo sólo se produce en las llamadas del primer nivel, cuando al terminar el contador se pone en cero...

... y ya estoy tecleando y manteniendo código repetido y mecánico para cada prólogo y epílogo.

miércoles, mayo 09, 2007 5:28:00 p. m.  
Blogger Ian Marteens said...

... y lo peor es que el mismo problema ocurre con las transacciones: si quiero que las operaciones que diseñe sean componibles, tengo que llevar un contador de nivel parecido.

Esa parte sí la tengo clara: no niego la existencia de "aspectos" que no son textualmente encapsulables. Lo que niego es la conveniencia y seguridad de una solución sencilla basada en un simple preprocesador. Las técnicas de inyección runtime son un poco más sofisticadas, porque si el framework de inyección es de fiar, puedes marcar declarativamente cuáles métodos pueden hacerle el juego (eso es MTS/COM+). Pero prefiero una solución estática, incorporada en el lenguaje.

miércoles, mayo 09, 2007 5:33:00 p. m.  
Blogger Ian Marteens said...

CodeGenerationIsaDesignSmell

Y no se trata de "generación de código"... a no ser que un compilador se vea como un "generador de código". Nunca verías el código "tejido", igual que no ves la destrucción automática de las variables locales de clase en C++ o la llamada a Dispose en el using de C# o el MoveNext en el foreach.

miércoles, mayo 09, 2007 5:36:00 p. m.  
Blogger Alfredo Novoa said...

¿! ¿Cómo? A lo mejor es ése mi problema: no lo veo. El ejemplo es mi propio editor de código: podría, a golpe de disciplina, haber evitado el uso de currentPosition, el campo, y limitarme a CurrentPosition, la propiedad (simplificando un poco). Pero no quería que se disparase el evento cada vez que asignase cualquier tontería temporal en la variable.

Solo hay dos cosas que pueden provocar un cambio de la posición: un evento de teclado y un evento del botón del ratón. Cuando salte uno de esos dos eventos levantas una bandera para que no vuelva a saltar el OnPositionChanged. Luego bajas la bandera al final de los eventos de ratón y del teclado: dos sitios, dos líneas.

A mi me parece que lo que intentas es una cosa de propósito tan específico que la mayoría de la gente no la va a usar nunca en la vida. Creo que hay cosas mucho más interesantes en las que invertir el tiempo.

La separación de preocupaciones de la que hablaba Dijkstra consiste en la separación entre corrección y rendimiento, cosa que no tiene nada que ver con esto de la AOP y es por supuesto mucho más importante. Ahí si que vale la pena invertir el tiempo.

miércoles, mayo 09, 2007 11:36:00 p. m.  
Blogger Ian Marteens said...

Cuando salte uno de esos dos eventos levantas una bandera para que no vuelva a saltar el OnPositionChanged. Luego bajas la bandera al final de los eventos de ratón y del teclado: dos sitios, dos líneas.

Pero observa que no es lo mismo: no evitas que una operación compuesta dispare el evento N veces, por cada operación individual. Con un evento informativo en un editor de texto no es grave. Piensa, en cambio, que se trata de una transacción automática. Piensa también en la verificación dinámica de invariantes de clase.

Lo que dice la AOP es que existe "código" (mira que no digo "operación" para no contaminar semánticamente la palabra) que no puede "centralizarse". Y es verdad. La que es mala es la solución típica, porque es completamente ortogonal al concepto de "recurso" y al encapsulamiento OOP.

jueves, mayo 10, 2007 12:00:00 a. m.  
Blogger Ian Marteens said...

Creo que hay cosas mucho más interesantes en las que invertir el tiempo.

... y en eso estoy de acuerdo: no es el recurso que se va a utilizar el 90% del tiempo. Pero si la propuesta resultase finalmente elegante, da la casualidad de que es muy fácil de implementar. Si la solución fuese parecida a la de AspectJ y demás, ni me lo planteaba. Es como lo de la exportación selectiva: montar un sistema más detallado como el de Eiffel sería complicado... pero resulta que una pequeña adición que no anula lo que ya existe significa un cambio importante en la funcionalidad.

Y, al menos, dentro del paradigma imperativo OOP, las diferencias entre lenguajes se han reducido mucho, entre otras cosas, por la uniformización forzada de las plataformas. En casos así, un poquiño termina por ser mucho.

¿Buscar cambios más radicales? Por supuesto, pero en un momento más adecuado. Y probablemente, ya no con Freya. Bajo supuestos de ese tipo, ¿para qué partir de una base como Delphi o Pascal? Todo en su momento.

jueves, mayo 10, 2007 12:07:00 a. m.  
Blogger Ian Marteens said...

Además, no se trata de un recurso esotérico, difícil de comprender y sin paralelos: es simplemente un trigger: una idea con la que ya están familiarizados muchos.

jueves, mayo 10, 2007 12:15:00 a. m.  
Blogger Alfredo Novoa said...

Pero observa que no es lo mismo: no evitas que una operación compuesta dispare el evento N veces, por cada operación individual.

Ya lo se, pero puedes tener varios niveles de eventos, en realidad lo que tu haces es crear un evento antes del evento.

Estoy de acuerdo en lo que dices de que no es generación de código, pero creo que cuando estás repitiendo código a mansalva en prólogos y epílogos eso puede ser una señal de mal diseño.

Con un evento informativo en un editor de texto no es grave.

Y este es el quid de la cuestión: si casi nunca es grave, según el principio del diseño cauteloso, no deberíamos añadir más complejidad al lenguaje.

Piensa, en cambio, que se trata de una transacción automática.

No se exactamente a que te refieres, pero seguro que hay soluciones mejores en la línea de SQL.

Piensa también en la verificación dinámica de invariantes de clase.

¿No te llega con poner aserciones en el "set" de las propiedades?

Pero si la propuesta resultase finalmente elegante, da la casualidad de que es muy fácil de implementar. ... pero resulta que una pequeña adición que no anula lo que ya existe significa un cambio importante en la funcionalidad.

En esto estoy completamente de acuerdo, pero creo que hace falta encontrar más ejemplos buenos que demuestren su utilidad.

En principio no estoy en contra de la idea, aunque creo que la sintaxis habría que pulirla un poco. Pero sigo escéptico hasta que no vea algún ejemplo de su utilidad a prueba de bomba.

¿Buscar cambios más radicales? Por supuesto, pero en un momento más adecuado. Y probablemente, ya no con Freya. Bajo supuestos de ese tipo, ¿para qué partir de una base como Delphi o Pascal?

Haciendo de abogado del diablo, también podría ser este un cambio demasiado radical para una variante de Pascal

Además, no se trata de un recurso esotérico

Si no estás familiarizado con la AOP algo esotérico si que es. No es un trigger como los de toda la vida, en realidad son dos.

Sugerencia: podrías tener triggers distintos para el prólogo y el epílogo. Pienso que el código se vería mucho menos raro. Un trigger "before update" y otro "after update".

jueves, mayo 10, 2007 11:13:00 a. m.  
Blogger Ian Marteens said...

Sugerencia: podrías tener triggers distintos para el prólogo y el epílogo.

Pero entonces siempre habría que usar campos para mantener el estado entre las dos partes del trigger. Tal y como lo veo, lo que se definen son dos paréntesis, y tiene sentido pensar en una continuidad entre una sección y la otra. Quizás sería mejor haber usado "prolog/epilog", pero no quiero meter palabras claves a lo tonto.

En realidad, incluso preferiría encerrar las dos secciones entre begin y end, y poner algún signo bien visible que actuase de divisor (visualízalo como un rectángulo separando las dos partes, en plan placeholder).

En todo caso, es importante saber que existe una continuidad... y poder verlo directamente, en vez de tener que hacer el ejercicio mental. Y si te extraña, mira lo que ocurre con un iterador de C#2: te ofrece un método, a primera vista, pero a tus espaldas lo segmenta calladamente en los estados necesarios. Un trigger sólo segmenta en dos partes. El iterador declarativo también podría simularse con técnicas OOP "tradicionales"... pero te obligaría a pensar en la máquina de estados de cada algoritmo de iteración particular, por lo que sale rentable dejar que sea el compilador quien se encargue del tema.

pero creo que cuando estás repitiendo código a mansalva en prólogos y epílogos eso puede ser una señal de mal diseño.

No: según la AOP, es un hecho ineludible, y que hasta ahora había caído en el punto ciego del ojo del programador.

Imagina que no existe el tratamiento de excepciones al estilo C++/Java/C#/Delphi. ¿Podrías resolver el manejo de errores encapsulando alguna abstracción? Pregunta retórica, y la respuesta es no. Puedes mejorar un poco la forma de informar al usuario, pero el hecho básico es que hay que untar todo el código de instrucciones que "atrapen" los códigos de error... y fastidiar y enredar el flujo de control.

Según la AOP, este problema habría sido otro candidato a ser tratado como "aspecto". Lo que ocurrió es que se ideó antes una solución ad hoc... al precio de introducir, como mínimo, tres nuevas instrucciones para este tema concreto (throw, try/finally, try/catch). Cada uno de los restantes "aspectos" más comunes podría intentar tratarse de esta manera, terminando con un monstruo de lenguaje y con la amenaza de descubrir algún otro "aspecto" en cualquier momento. O, por el contrario, la solución AOP: una misma solución aplicable a todos los aspectos (con colaboración del programador).

¿No te llega con poner aserciones en el "set" de las propiedades?

:) No, y por la misma razón por la que necesito "consolidar" el lanzamiento de eventos. En este caso, porque los invariantes sólo deben verificarse para las llamadas públicas. Cuando el IP entra "dentro de la tienda", puede poner la nevera patas arriba y bailar un zapateo encima del mostrador. Cuando salga de la tienda, si la clase ha cumplido con su contrato, da igual lo que haya hecho dentro. Es que no interesa estar jodiéndole la vida y comprobando invariantes a destiempo.

Ese es el quid: necesito el mismo patrón de generación de código para las invariantes y para este invento. Y hay más ejemplos de este tipo.

jueves, mayo 10, 2007 5:11:00 p. m.  
Blogger Alfredo Novoa said...

Pero entonces siempre habría que usar campos para mantener el estado entre las dos partes del trigger.

Si es un campo normal tendría que ser una pila y habría que mantenerla a mano lo que es un coñazo, y si no lo haces bien montarías un buen lío. O sea que lo del campo normal es mala idea.

Y si te extraña, mira lo que ocurre con un iterador de C#2: te ofrece un método, a primera vista, pero a tus espaldas lo segmenta calladamente en los estados necesarios.

Ya, pero lo que importa es que sea un método a primera vista. Tu trigger es una cosa muy rara. Yo creo que no se debería llamar trigger por que es algo completamente diferente.

No: según la AOP, es un hecho ineludible, y que hasta ahora había caído en el punto ciego del ojo del programador.

Pues yo siempre he conseguido eludirlo.

El caso es que casi nadie presta atención a la AOP. Tratan de resolver problemas que casi nadie tiene y que preocupan todavía menos.

Según la AOP, este problema habría sido otro candidato a ser tratado como "aspecto". Lo que ocurrió es que se ideó antes una solución ad hoc...

Eso se podría decir de cualquier construcción de cualquier lenguaje, es una chorrada. Desde luego los lenguajes están mejor tratando las excepciones como lo hacen que usando un preprocesador raro.

Cada uno de los restantes "aspectos" más comunes podría intentar tratarse de esta manera, terminando con un monstruo de lenguaje y con la amenaza de descubrir algún otro "aspecto" en cualquier momento.

Así es como funcionan casi todos los lenguajes y tampoco crecen tanto. Cuando a alguien se le ocurre una construcción que realmente vale la pena pues se añade y ya está, pero eso no ocurre todos los días ni muchísimo menos.

:) No, y por la misma razón por la que necesito "consolidar" el lanzamiento de eventos. En este caso, porque los invariantes sólo deben verificarse para las llamadas públicas. Cuando el IP entra "dentro de la tienda", puede poner la nevera patas arriba y bailar un zapateo encima del mostrador. Cuando salga de la tienda, si la clase ha cumplido con su contrato, da igual lo que haya hecho dentro.

Pues vaya unas invariantes :-)

En el caso extraño en el que tengas que corromper temporalmente una invariante dentro de un procedimiento, pues lo haces en una variable local y listo. Son dos líneas para una cosa que no te va a pasar todos los años, y además está el tema del multihilo que no es muy amigo de variar las invariantes.

miércoles, mayo 16, 2007 2:28:00 p. m.  
Blogger Alfredo Novoa said...

Pues yo siempre he conseguido eludirlo.

Excepto con los Visitors, que ahora mismo me tienen frito. Menos mal que el IDE se encarga de generar casi todo el código repetitivo.

miércoles, mayo 16, 2007 4:49:00 p. m.  

Publicar un comentario

<< Home