Continuamos buscando mas calidad y mejor desempeño en el IDE y las aplicaciones generadas, con Delphi 2007 for Win32 tenderás mas desempeño en tiempo de desarrollo y en la aplicación final comparado a Delphi 7.
Novedades en el compilador y el lenguaje desde Delphi 7
Directiva inline
Se trata de una nueva directiva que va aumentar el desempeño del compilador con solo agregar la palabra reservada “inline”. En este caso, el método es expandido, evitando su lectura a todo momento. Esta forma de acceso presenta mejores resultados para métodos pequeños, fuera del alcance de la unit o para rutinas con muchos parámetros. Para el caso de rutinas mas grandes, se recomienda hacer una análisis de costo-benefició en cuanto a su utilización
A continuación se muestra el código una aplicación de consola, utilizando “inline” en la función Max.
program InlineDemo; {$APPTYPE CONSOLE} uses MMSystem; function Max(const X,Y,Z: Integer): Integer;inline begin if X > Y then if X > Z then Result := X else Result := Z else if Y > Z then Result := Y else Result := Z end; const Times = 10000000; // 10 millón var A,B,C,D: Integer; Start: LongInt; i: Integer; begin Random; // 0 A := Random(4242); B := Random(4242); C := Random(4242); Start := TimeGetTime; for i:=1 to Times do D := Max(A,B,C); Start := TimeGetTime-Start; writeln(A,', ',B,', ',C,': ',D); writeln('Calling Max ',Times,' times took ',Start,' milliseconds.'); readln end. |
Al ejecutar esté código y comparar los resultados se encuentra una reducción importante en el tiempo de respuesta. Los siguientes resultados se obtuvieron después de que se ejecutó la función Max 10 millones de veces en una computadora Pentium M 1.8GHz con 2GB RAM. . Aunque estos valores pueden cambiar una computadora a otra, las proporciones son similares.
Con inline | Sin inline |
25 milisegundos | 68 milisegundos |
De acuerdo con lo visto en la tabla anterior, se observa que al utilizar la capacidad “inline”, el código compilado puede aumentar, su rendimiento más de un 50%.
Sobrecarga de operadores
type TMyClass = class class operator Sumar(a, b: TMyClass): TMyClass; // Sumar las clases de tipo TMyClass class operator Restar(a, b: TMyClass): TMyclass; // Restar las clases de tipo TMyClass class operator Implicit(a: Integer): TMyClass; // Conversión implícita para la clase de tipo TMyClass class operator Implicit(a: TMyClass): Integer; // Conversión implícita de la clase TmyClass para Integers. class operator Explicit(a: Double): TMyClass; // Conversión explicita de un Double para la clase TMyClass end; // Ejemplo de implementación del método Sumar class operator TMyClass.Add(a, b: TMyClass): TMyClass; begin // ... end; var x, y: TMyClass; begin x := 12; // Conversión implícita de un Integer, ejecuta el método Implicit y := x + x; // Ejecuta TMyClass.Add(a, b: TMyClass): TMyClass b := b + 100; // Ejecuta TMyClass.Add(b, TMyClass.Implicit(100)) end; |
Class Helpers
Los Class Helpers permiten extender clases sin utilizar herencia. Este recurso es importante, pues algunas clases, llamadas clases Selead, no pueden ser heredadas. La utilización de este nuevo recurso es muy apreciada. A continuación se muestra un ejemplo.
type TMyClass = class procedure MyProc; function MyFunc: Integer; end; ... procedure TMyClass.MyProc; var X: Integer; begin X := MyFunc; end; function TMyClass.MyFunc: Integer; begin ... end; ... type TMyClassHelper = class helper for TMyClass procedure HelloWorld; function MyFunc: Integer; end; ... procedure TMyClassHelper.HelloWorld; begin writeln(Self.ClassName); // Self hace referencia al tipo TMyClass y no TMyClassHelper end; function TMyClassHelper.MyFunc: Integer; begin ... end; ... var X: TMyClass; begin X := TMyClass.Create; X.MyProc; // Ejecuta TMyClass.MyProc X.HelloWorld; // Ejecuta TMyClassHelper.HelloWorld X.MyFunc; // Ejecuta TMyClassHelper.MyFunc |
Vale la pena observar que la referencia es siempre a la clase TMyClass. El compilador sabe cuando ejecutar la llamada a TMyClassHelper.
Strict private y Strict protected
Ahora en Delphi Win32 y .NET se tienen dos formas adicionales de determinar la visibilidad de los atributos de una clase: strict private y strict protected.
Strict private: todos los atributos de la clase son visibles únicamente en la clase que fueron declarados. Estos atributos no estarán visibles para métodos declarados en la misma unit y para aquellos que no forman parte de la clase.
Strict protected: Específica que los atributos da clase son visibles para la propia clase y sus descendentes.
Los Records ahora soportan métodos
Las capacidades de los registros (records) han sido incrementadas, pasando a ser casi lo mismo que una clase (Class), con soporte ha:
Constructores.
Sobre posición de operadores.
Declaración de métodos no-virtuales.
Métodos y propiedades estáticos.
Veamos un ejemplo de la implementación de un registro con estas nuevas características:
Type TMiRegistro = Record Type TTipoColor = Integer; Var Rojo : Integer; Class Var Azul : Integer; Procedure imprimirRojo(); Constructor Create(Val : Integer); Property pRojo : TTipoColor Read Rojo Write Rojo; Class Property pAzul : TTipoColor Read Azul Write Azul; End; Constructor TMiRegistro.Create(Val: Integer); Begin Rojo := Val; End; Procedure TMiRegistro.imprimirRojo; Begin WriteLn('Rojo: ', Rojo); End; |
De acuerdo a lo visto anteriormente los registros pueden utilizar muchas de las funcionalidades que hasta entonces eran exclusivas de las clases, sin embargo los registros no son clases y tienen muchas diferencias:
Los Registros no tienen soporte a herencia;
Los Registros pueden tener partes variable, las clases no;
Los Registros son tipos de datos y pueden, entre otras cosas, ser copiados, clases no;
Los Registros no tienen destructores;
Los Registros no tienen soporte a métodos virtuales;
Class abstract, Class sealed, Class const, Class type, Class var, Class property
Diversas nuevas formas de declaración de clases, tipos, variables y propiedades.
Class abstract -Especifica una clase abstracta.
Class sealed - Especifica que la clase no puede ser heredada.
Class const - Especifica una constante para la clase, que puede ser accedida sin necesidad de crear instancias de la clase.
Class type -Define uno tipo para la clase que puede ser accedida sin necesidad de crear instancias de la clase.
Class var -Define una variable en el scope de la clase que puede ser accedida sin necesidad de crear instancias de la clase.
Class property -Define propiedad que puede ser accedida sin la necesidad de crear instancias de la clase.
Nested Clases
De una forma más didáctica, las clases Nested (o anidadas) serian como subclases, que pueden ser accedidas a partir de una clase y su tipo declarado dentro del contexto. Ejemplo de clase:
type TOuterClass = class strict private myField: Integer; public type TInnerClass = class public myInnerField: Integer; procedure innerProc; end; procedure outerProc; end; |
El método de la clase interna se implementa de la siguiente manera:
procedure TOuterClass.TInnerClass.innerProc; begin ... end; |
Finalmente el siguiente código muestra como acceder al método que está en la clase anidada:
var x: TOuterClass; y: TOuterClass.TInnerClass; begin x := TOuterClass.Create; x.outerProc; ... y := TOuterClass.TInnerClass.Create; |
Métodos finales
Los Métodos declarados con final especifican que el mismo método no pode ser sobrepuesto (override) en clases descendentes, sin embargo se puede declarar uno método con el mismo nombre siendo virtual.
Static class method
Son clases que cuando son declaradas como Static no necesitan ser instanciadas para ser accedidas.
For … in
Ahora es posible hacer un for directo en objetos que contengan collections, arrays, expresiones string y expresiones de tipo set, tanto para Delphi Win32 como para .NET. Ejemplos:
Ejemplo: Iteración en un Array
var IArray1: array[0..9] of Integer = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); I: Integer; begin for I in IArray1 do begin // Hacer algo aquí... end; |
Ejemplo: iteración en un String:
var C: Char; S1, S2: String; OS1, OS2: ShortString; AC: AnsiChar; begin S1 := ‘Nuevos recursos en Delphi 2007'; S2 := ''; for C in S1 do S2 := S2 + C; if S1 = S2 then WriteLn('SUCESSO #1'); else WriteLn('FALHOU #1'); OS1 := 'Migrando de Delphi 7 para Delphi 2007...'; OS2 := ''; for AC in OS1 do OS2 := OS2 + AC; if OS1 = OS2 then WriteLn('EXITO #2'); else WriteLn('FALLOU #2'); end. |
Novedades en el IDE desde Delphi 7
El IDE trae una serie de novedades, como:
MSBuild à controle todo el proceso de compilación de su aplicación, los pasos antes y después de compilar un proyecto, esto es excelente para los desarrolladores que necesitan automatizar la compilación. Cuando abrir un proyecto en Delphi 2007, automáticamente el mismo va ser convertido para el nuevo formato y con la extensión DPROJ, para soportar MSBuild.
Vista e XP Themes à el IDE soporta los temas para Windows Vista y XP. Ahora es default y puedes habilitar y deshabilitar a través de las opciones de proyecto.
Project Manager à el project manager soporta múltiplas selecciones y con esto permite abertura, grabación y borrar mas de un archivo simultáneamente.
File Browser à con el File Browser no tenemos que abrir Windows Explorer o ir al menú File Open todo tiempo para abrir un archivo, pues File Browser ofrece acceso directo a su árbore de carpetas de dentro del IDE.
Live Templates, Block Completion, indicador de líneas alteradas
Los nuevos recursos de live template extienden la capacidad de crear plantillas de código en Delphi. Estas plantillas son creadas en un archivo XML y ayudan a programar escribiendo menos código.
![image](//lh3.ggpht.com/erickmueses/SJsH1UPG1eI/AAAAAAAAACE/Oh-BlpjlSPo/image_thumb%5B11%5D.png)
Figure 1. Creando un try..finally utilizando la capacidad de LiveTemplates.
La capacidad de block completion es uno de los recursos que habilitan el begin y end automático. ¿Quién nunca se perdió con begin y end?
En la figura 1, tenemos una marcación amarilla y otra verde, la amarilla representa las líneas que fueron cambiadas, mientras las verdes son líneas que no cambiaran.
Histórico de los cambios
Independiente de una herramienta de control de versiones, las alteraciones en fuentes son versionadas localmente, permitiendo la comparación entre las versiones.
Figura 2. Versionamento local y comparación entre 2 fuentes
Depurador
El nuevo depurador trae diversas mejoras en variables locales, call stack y otros, sin embargo una de las principales novedades es la visualización en árboles. Véase un ejemplo:
Figura 3. Depurando una aplicación y visualizando las variables en TreeView
También es posible configurar la barra de enrollamiento de la ventana de eventos y abrir separadamente cada ítem de la ventana de CPU, con un simples drag-and-drop presionando la tecla CTRL, la ventana se queda transparente, facilitando la lectura del código durante la depuración.
Refactoring
Esta es una de las capacidades que más les gustan a los usuarios de Delphi 7, ya que a través de los refactorings se pueden renombrar clases, variables y métodos de manera que al hacer un cambio de nombre se cambien automáticamente todas las líneas de código en los que se hacía referencia al nombre anterior. Mediante esta capacidad de refactoring es posible también cambiar los parámetros de clases, seleccionar parte del código y generar un método a partir del bloque seleccionado, también es posible mover métodos de una clase a otra, entre muchas otras cosas.
Unidades de Prueba
La integración con unidades de pruebas a través de DUnit facilitan la creación de métodos y en general código de pruebas que se usa para probar el código de la propia aplicación. Esto facilita la notablemente la prueba de las aplicaciones, pues es como si se tuviese un “programa que prueba al programa”.
SQL Window - Query Builder
Ahora a través del DataExplorer podemos construir querys visualmente utilizando el Query Builder, desde simples sentencias select hasta complejos querys utilizando joins.
Figure 4 SQL Window integrado a Query Builder