martes, abril 10, 2007

Exportación selectiva

VisibilityMientras releo el código fuente del sistema de ventanas que mencionaba hace unos días, me reafirmo en mi idea sobre cuál es la primera característica que le añadiría a los lenguajes .NET: la exportación selectiva de sus miembros.
Esta idea, como tantas otras, la conozco a través de Eiffel. En las clases de este lenguaje no existen las típicas secciones private, public o protected, popularizadas por C++. Los miembros de una clase se agrupan en secciones encabezadas por la palabra clave feature (debería tener una "s" final para estar en tercera persona del singular; lo mismo ocurre con require o ensure). Estas cabeceras de sección pueden incluir una lista de clases que pueden utilizar los miembros agrupados bajo ella:
class FULANA
feature

feature { MENGANA, ZUTANA }

feature { NONE }

end
La idea que me ronda no es eliminar el actual sistema de niveles de acceso. En principio, sólo sería necesario ampliar las posibilidades del nivel internal. Ahora mismo, cualquier miembro declarado internal está al alcance de cualquier otra clase definida en el mismo ensamblado. Barra libre, por así decirlo. Imposible saber quién está toqueteando indebidamente el método X y por qué razón lo hace. Menos mal que existe un comando Buscar todas las referencias... pero no es lo mismo.
Lo peor de todo es que existen poderosos motivos para que un programador decida declarar métodos y propiedades internas... cargándose la mantenibilidad del sistema que está programando. Usted ha comenzado a programar su sistema como una aplicación monolítica. Luego se ha dado cuenta de que puede manejar la aplicación desde otra aplicación independiente: basta con utilizar el ejecutable como si fuese una biblioteca de clases. El compilador de línea de comandos de Freya, por ejemplo, es un fichero ejecutable que implementa una aplicación de consola, pero el entorno de desarrollo carga el ejecutable como si se tratase de un ensamblado en formato DLL. El problema es que, casi siempre, las clases dentro del ejecutable habrán sido originalmente diseñadas como clases públicas. Bien, usted esconde las clases A y B pero, ¡qué mala pata!, la clase C tiene una propiedad pública que devuelve un objeto de tipo A. No podemos redeclarar esa propiedad como privada, porque medio programa la utiliza... pero tampoco nos interesa que esté al alcance de cualquier mindundi. ¿La solución? El programador redeclara la propiedad como internal... sin darse cuenta de que acaba de hundirse hasta la cintura en el fango.
Mi propuesta consiste en mantener la misma sintaxis y semántica que ahora tienen los restantes niveles de visibilidad en .NET, y además permitir que el modificador internal pueda ir acompañado por una lista de clases. Tenga presente que el efecto de internal se limita al ensamblado donde se declara. Por lo tanto, este tipo de propuesta es ideal: se logra un efecto muy beneficioso sin necesidad de afectar el funcionamiento de los lenguajes de la plataforma que decidan no secundar la idea.

Etiquetas: , ,

10 Comments:

Blogger Alfredo Novoa said...

Mucho mejor aun sería que a cada componente de un tipo se le pudiese asignar una lista de los operadores (procedimientos) que tienen acceso a él. De esa forma nos podríamos liberar de la absurda limitación de que un método solo pertenece a una clase.

Es decir que los operadores ya no tendrían que ir empaquetados dentro de las clases y tendríamos lo que a veces se conoce como "multimétodos" o "multiple dispatch".

Si además nos cargamos la grotesca identidad de los objetos (los punteros) entonces estaríamos dando un gran paso para superar de una vez la primitiva OO.

martes, abril 10, 2007 3:42:00 p. m.  
Blogger Ian Marteens said...

tipo se le pudiese asignar una lista de los operadores (procedimientos) que tienen acceso a él.

¿Cómo el truco de los friends de C++ para operadores declarados fuera de la clase? Con el recurso que propongo, sería inmediato.

Es decir que los operadores ya no tendrían que ir empaquetados dentro de las clases

Hmm, no lo veo muy claro. De entrada, el CLR tiene unas reglas al respecto, aunque supongo que es posible saltárselas: es posible tener "métodos globales" en el CLR...

tendríamos lo que a veces se conoce como "multimétodos" o "multiple dispatch".

... pero lo que no veo es eso: ¿binding estático a la implementación, como en C++/C#, o algún mecanismo de late binding basado en los dos (o tres, o cuatro) operandos? ¿Conoces algún artículo online para echarle un vistazo?

:) Por cierto, acabo de someterme al castigo de ver el vídeo-entrevista de Calvert a Hejlsberg:

1- Joder. Al final Microsoft se quedó con Borland. Con todo, menos el nombre, claro, que no le hacía falta. Chuck J. está con Cider. Thorpe, intrigando con Internet. Es a Microsoft a quien habría que pedirle que desarrollase la próxima versión de Delphi (os quejáis de mí, pero ya hay .NET Framework 3.5 y CodeGear no tiene siquiera un compilador para la 2.0).

2- No sé... pero tengo la impresión de que Anders se va cabreando a medida que avanza la entrevista. Lo dejé a la mitad porque Calvert estaba obligando a Anders a moverse en círculos, y éste reaccionaba elevando la voz y gesticulando cada vez más. A lo mejor he hecho mal y me he perdido lo mejor del vídeo: el momento en que Hejlsberg agarra por el cuello a "Charlie" y lo zarandea.

miércoles, abril 11, 2007 1:52:00 a. m.  
Blogger Alfredo Novoa said...

¿Cómo el truco de los friends de C++ para operadores declarados fuera de la clase? Con el recurso que propongo, sería inmediato.

Si, pero esto tendría un "granulado" más fino.
Quienes realmente tienen que acceder o no a los componentes internos de un tipo son los operadores, no otros tipos.

Hmm, no lo veo muy claro. De entrada, el CLR tiene unas reglas al respecto, aunque supongo que es posible saltárselas: es posible tener "métodos globales" en el CLR...

Hombre, esto ya es un cambio bastante radical, pero soluciona uno de los defectos más graves de la mayoría de los lenguajes OO.

Si que se podría implementar con métodos globales sin mucho problema.

... pero lo que no veo es eso: ¿binding estático a la implementación, como en C++/C#, o algún mecanismo de late binding basado en los dos (o tres, o cuatro) operandos?

Lo segundo.

¿Conoces algún artículo online para echarle un vistazo?

Busca "multiple dispatch" en Google o la Wikipedia.

Estos días estoy mirando el lenguaje Dylan y está bastante interesante. Otros lenguajes con multimétodos son: Common Lisp, Nice, Slate y Cecil.

Con los multimétodos el patrón "visitor" (que uso por todas partes en mi compilador) se vuelve innecesario.

En realidad la mayoría de los patrones se vuelven innecesarios con los lenguajes dinámicos.

miércoles, abril 11, 2007 8:42:00 a. m.  
Blogger Ian Marteens said...

Si, pero esto tendría un "granulado" más fino.
Quienes realmente tienen que acceder o no a los componentes internos de un tipo son los operadores, no otros tipos.


¡! Pero eso ya lo tiene C++, que permite declarar friend una función.

miércoles, abril 11, 2007 10:02:00 a. m.  
Blogger Alfredo Novoa said...

Ah, te entendí mal. Si, algo como los friends de C++. Yo lo usaría como único mecanismo de vinculación entre operadores y tipos. Teniendo eso, empaquetar los operadores con los tipos ya no tiene sentido.

miércoles, abril 11, 2007 10:59:00 a. m.  
Blogger Alfredo Novoa said...

De todas formas siempre se le podría dar un granulado más fino que el de los friends de C++.

miércoles, abril 11, 2007 11:25:00 a. m.  
Blogger Ian Marteens said...

Tengo como diez ventanas abiertas ahora mismo con artículos sobre "multiple dispatch". Sí, conocía la idea desde los tiempos de la universidad, pero no había vuelto a darle "cocción".

Teniendo eso, empaquetar los operadores con los tipos ya no tiene sentido.

No debería decir nada antes de enterarme un poco más. A priori, las pegas que se me ocurren tienen que ver más con la facilidad de crecimiento de un sistema de este tipo. Quiero decir: no veo claro que ocurriría en situaciones prácticas.

Me explico un poco más: la gente que trabaja con lenguajes funcionales, por poner un ejemplo muy concreto, suele reducir la valoración de un lenguaje a su expresividad. Olvidan que una propiedad aparentemente tan inocua como la distribución espacial del propio texto del programa, influye tanto o más que la expresividad en la legibilidad, robustez y extensibilidad de un sistema. Y no estoy diciendo que esto sea un problema del "multiple dispatch", sino que los artículos que estoy viendo no mencionan (excepto en un párrafo de uno de ellos) este asunto.

Pero es muy pronto para que pueda decir algo inteligente sobre el tema.

miércoles, abril 11, 2007 11:50:00 a. m.  
Blogger Ian Marteens said...

:) Como anécdota, ahora que se respira tanto entusiasmo por la aparición de un Delphi para PHP:

Nancy typing

miércoles, abril 11, 2007 11:53:00 a. m.  
Anonymous Anónimo said...

No se si este es el procedimiento correcto, pero acabo de descubrirlo y te lo cuento.
Hay una errata en el manual de ejercicos de la serie C, en la pagina 48, linea 35 donde dice 'where EmployeeID = @Original_EmployeeID" debe decir "where EmployeeID = @EmployeeID".
Si este no es el sitio o procedimiento para estas cosas, por favor comunicamelo.

Un Saludo, animo y a acabar el curso.

jueves, abril 12, 2007 9:20:00 a. m.  
Blogger Ian Marteens said...

No se si este es el procedimiento correcto

Por el contrario, muchas gracias. Estoy preparando también nuevo libro, probablemente para finales de año, y las erratas son siempre una pesadilla.

sábado, abril 14, 2007 3:20:00 a. m.  

Publicar un comentario

<< Home