Supongo que todos quienes han diseñado o participado en el diseño de un lenguaje, tendrán distintos motivos para haberse embarcado en tal aventura. En mi caso, la inspiración me llegó al conocer la rebuscada sintaxis añadida a Delphi para declarar campos y métodos estáticos, compatibles con la plataforma .NET. En este artículo explicaré la estructura de una clase en lo que respecta a sus niveles de visibilidad, la separación entre recursos estáticos y a nivel de instancia, y los modificadores aplicables a las declaraciones de métodos. VISIBILIDADDelphi ha ofrecido tradicionalmente los tres niveles clásicos de visibilidad, inspirados en el modelo de objetos de C++. Aparte de ellos, ofrece published, que es una variante de public con información adicional de tipos en tiempo de ejecución (RTTI), y durante poco tiempo jugueteó con automated, un invento apresurado y chapucero para tratar con Automatización OLE, que fue declarado obsoleto, pernicioso y sumamente contagioso a partir de Delphi 3. En contraste, el modelo de objetos de .NET exige al menos cinco niveles de visibilidad. Algunos nombres de niveles se utilizan en ambos modelos, pero el significado difiere un poco. Lo que hizo Delphi.NET fue adaptar y extender su propio modelo, en vez de adoptar directamente el nuevo modelo, en aras de la compatibilidad con el código para Windows nativo. Freya conserva, a regañadientes, los cinco niveles de visibilidad existentes en Delphi.NET. A saber:
Por supuesto, desaparece la sección published de Delphi, que fue un error de diseño desde el principio, al mezclar dos conceptos diferentes como información de tipos en tiempo de ejecución y visibilidad. Uno de las consecuencias más nocivas de published es que cuanto componente se deja caer sobre un módulo de datos, puede ser usado y modificado desde cualquier otra parte de la aplicación, dificultando el encapsulamiento correcto de la funcionalidad de ésta. CLASES E INSTANCIASComo he mencionado al principio, la "culpa" de la existencia de Freya la tiene, en su origen, la sintaxis utilizada por Delphi para declarar campos y métodos estáticos. Primero, es necesario aclarar la diferencia entre un método estático y un método de clase, porque estos últimos ya existían en Delphi nativo. Aunque ambos tipos de métodos se aplican sobre un nombre de clase, en el caso del método estático no hay un parámetro oculto Self, como en los métodos de instancias; los métodos de clase sí utilizan un parámetro oculto Self, aunque éste apunta a una referencia de clase, en vez de apuntar a un objeto. Los métodos de clase se declaraban en Delphi (y todavía se declaran) añadiendo un prefijo a la declaración: class procedure MetodoClase(Parametro: Integer); NOTA
Los campos estáticos, además, no tenían siquiera un antecedente de este tipo en Delphi clásico, que obligaba a usar variables globales a modo de sustitución.
Al parecer, cuando el equipo de Delphi.NET tuvo que extender la sintaxis de la clase para permitir recursos estáticos, se tomaron como punto de partida las secciones de declaraciones clásicas de Pascal, y se decidió que lo apropiado era anidar estas secciones dentro de una declaración de clase: // ATENCION: Delphi.NET type AClass = class private var // Campos "normales", a nivel de instancia Field1, Field2: Integer; Field3, Field4: string; class var // Campos estáticos, a nivel de clase Field5, Field6: Double; Field7: Boolean; private // Todavía se permite el estilo "antiguo" Field8: Integer; protected // ¡Los métodos estáticos siguen reglas muy diferentes! class function DoThat(Value: Integer): string; static; ... end; Si no ha pegado un salto al leer este listado, es que tiene usted una piel envidiablemente gruesa. Estos son algunos de los problemas con este tipo de declaraciones:
Y hay más razones en contra de esta sintaxis. Podemos interpretar que los métodos y campos estáticos son en realidad miembros de instancia de otra clase asociada a la clase principal, para la cual solamente se crea una sola instancia. Bajo esta luz, al declarar una clase con miembros estáticos, estamos realmente declarando dos clases, una de las cuales sería un singleton subordinado. De hecho, la implementación de los métodos de clase tradicionales en Delphi.NET aprovecha internamente esta interpretación. Si aceptamos este punto de vista, y quisiéramos establecer una clasificación jerárquica de los distintos tipos de recursos declarables en una clase, obtendríamos el siguiente árbol de categorías como clasificación más natural: 1. Todas las declaraciones 1.1. Declaraciones a nivel de instancia 1.1.1. Secciones de visibilidad 1.2. Declaraciones estáticas 1.2.1. Secciones de visibilidad Es decir, en la interpretación más "natural" (dicho sea con todas las precauciones), el anidamiento de declaraciones tendría que tener lugar ¡en el sentido contrario al usado en Delphi.NET! De todos modos, tanto anidamiento es incómodo, sin importar el orden en que tenga lugar. La solución adoptada por Freya está situada a mitad de camino entre lo que sería natural en Pascal y lo que hacen Java y C#: mezclamos los atributos de visibilidad con el "nivel" de la declaración, pero sacamos factor común para toda una sección. Es mejor ilustrarlo mediante un ejemplo: // Freya MiClase = class protected ... public ... static strict private ... static public ... end. Cada sección de visibilidad puede ir precedida, o no, por el modificador static. Cuando este modificador está presente, todas las declaraciones de la sección se consideran estáticas. Los métodos de clase pueden declararse en cualquier sección de la clase, y siguen identificándose mediante el prefijo class. NOTA
La sintaxis de los constructores se trata en este otro artículo, junto con las referencias de clases. Freya incluye los constructores "tradicionales", los constructores virtuales de Delphi, y los constructores estáticos de clases de .NET.
MODIFICADORES DE METODOSVeamos ahora la sintaxis formal de una declaración de método en Freya: [class] (procedure|function) method-identifier [parameters][: return-type]; [modifiers ;] La parte más novedosa es la lista de modificadores que puede ir asociada a un método. Hay cinco modificadores disponibles en Freya, y de ellos, hay un grupo de cuatro modificadores mutuamente excluyentes:
Aparte de estos cuatro modificadores, Freya utiliza también el modificador new, que puede utilizarse aislado o en compañía de virtual o abstract. new tiene el mismo significado que en C#, y aproximadamente el mismo que reintroduce en Delphi clásico: se debe incluir cuando un nuevo método enmascara un método similar existente en un ancestro. El orden relativo de los modificadores no es significativo: da lo mismo new virtual que virtual new. Note, de paso, que Freya no necesita la directiva overload. El CLR de .NET ofrece soporte nativo para la sobrecarga de nombres, y no es necesario que el compilador utilice la conocida técnica de name mangling. Por el contrario, los lenguajes como Eiffel, que no soportan la sobrecarga de nombres de métodos, son los que han tenido que realizar adaptaciones para poder acceder a métodos sobrecargados definidos en otros lenguajes. PARAMETROSNo hay sorpresas en la sintaxis de los parámetros formales y el opcional tipo de retorno, excepto que desaparecen muchas opciones tradicionales, como los parámetros sin tipo. Los modificadores out y var se utilizan para los parámetros de salida y los parámetros por referencia. No existe un equivalente en Freya del modificador params de C#... porque es innecesario. A cambio, Freya hereda de Delphi la posibilidad de construir vectores "al vuelo": // Freya
System.Console.WriteLine('{1}, {0}', [Cliente.Nombre, Cliente.Apellidos]); C# necesita params porque el constructor de vectores es mucho más engorroso: // C#
System.Console.WriteLine("{1}, {0}", new object[] {Cliente.Nombre, Cliente.Apellidos}); Por último, Freya no exige que repitamos el modificador var al pasar un parámetro por referencia a un método, como sí ocurre en C#. Esta medida adoptada por C# mejora la legibilidad del código, pero va totalmente en contra del estilo histórico de Pascal y sus derivados... y obliga a teclear un poco más. Freya permite la repetición del modificador var al aplicar métodos con parámetros pasados por referencia, pero no obliga a ello. NOTA
He omitido deliberadamente cualquier referencia a clases y métodos genéricos en este artículo.
Vea también:
|