Expresiones regulares: Novedad en XE (Parte I)

abril 3, 2011 en Artículos, ¿Sabías que...?, Delphi, Entrada Diario, XE

Una de las novedades que ha introducido XE, es la integración dentro de la llamada RTL (Run Time Library) de Delphi, de las Expresiones regulares, aspecto que ya estaba integrado en nuestro IDE, a través de una de las opciones de búsqueda pero que no se había hecho disponible hasta hoy de forma oficial dentro del entorno para nuestro uso en los proyectos.

En la ayuda de Delphi podeis acceder con este link, [ms-help://embarcadero.rs_xe/rad/VCL_and_RTL_Changes_for_XE.html], en donde se recogen los cambios de versión o novedades dentro de la VCL y RTL citados en el parrafo anterior.

Para empezar a trabajar con las Expresiones Regulares basicamente, tendremos que añadir a la clausula uses del módulo del proyecto que va a utilizarlas, la unidad RegularExpressions, que es la unidad que declara e implementa las clases que vamos a necesitar. Si accedeis a la información de la ayuda en linea, vereis que aparecen un conjunto de clases (7):

TGroup Un registro que contiene el resultado de una coincidencia con una porción de una expresion regular.
TGroupCollection Colección de instancias de TGroup.
TGroupCollectionEnumerator Contiene funciones y propiedades para recorrer los resultados de la colección de grupos.
TMatch Un registro conteniendo los resultados de una coincidencia con la expresión regular.
TMatchCollection Colección de instancias de TMatch.
TMatchCollectionEnumerator Contiene funciones y propiedades para recorrer los resultados de la colección de coincidencias.
TRegEx Un registro para manejar las expresiones regulares,

Lo cual, en principio no resulta demasiado claro, al menos si no se puede ver en un ejemplo o se ha trabajado anteriormente con Expresiones Regulares. Afortunadamente existen algunos ejemplos dentro de la ayuda bastante útiles por lo que considero que podemos remitirnos a ellos como guía.

Dentro de la dockwiki de embarcadero podéis acceder al link que contiene ejemplos nuevos propios de Xe http://docwiki.embarcadero.com/CodeExamples/en/Category:XE y ya dentro de esta página, yo eligiría para empezar a entender como se relacionan las distintas clases el vínculo: http://docwiki.embarcadero.com/CodeExamples/en/TMatchCollectionCount_(Delphi)

Pero antes de ver cualquier ejemplo, parece que lo mas apropiado es hacer una pequeña reseña al concepto de Expresiones Regulares, de forma que quien se ha podido acercar por primera vez al tema sepa de que hablamos. Así que, podemos dividir este artículo en dos entradas: ésta para intentar comprender las expresiones regulares y una segunda parte abordando el conjunto de clases de la unidad Regular Expressions.

Para empezar, decir simplemente que las expresiones regulares se remontan a la decada de 1950, en la que Kleene, lógico y matemático estadounidense, daba los primeros pasos al relacionar expresiones regulares y autómatas finitos.

Una expresión regular representa un patrón de cadenas de caracteres y se define por el total del conjunto de cadenas con las que concuerda o coincide. Es decir, a partir de un patrón fijado por nosotros encontramos un numero indeterminado de cadenas que podrían coincidir con el y que confortan lo que podríamos considerar el dominio de aplicación de dicho patrón o lenguaje de la expresión.

Un ejemplo: la expresión regular ‘abc|d’ admitiría las cadenas ‘abc’ ó ‘d’  pero no otras, dentro de ese lenguaje.

En la práctica, si consideraramos dentro de nuestro patrón los caracteres ASCI o cualquier subconjunto del mismo, podríamos denominar a dicho conjunto como su alfabeto. Imaginad uno cualquiera de esos alfabetos (|a|, |b|.. |z|),  veremos que existen 3 operaciones básicas que podríamos considerar respecto a la forma en que se interrelacionan: la primera podría ser la la selección de alternativas, ya vista en el ejemplo anterior. El caracter ‘|’ nos ha permitido discriminar dos opciones. Este tipo de caracteres que tienen un significado especial reciben el nombre de Metacaracteres o metasímbolos y no serían legales en el alfabeto, a no ser que exista otro metacaracter que desactive su valor especial. La segunda operación básica sería la Concatenación, que se formaría  por yuxtaposición (sin metacaracter). Esta operación nos permitiria enlazar o unir caracteres para formar una expresión. En el ejemplo anterior, ha permitido considerar ‘abc’ como agrupación de varios caracteres del alfabeto. Finalmente, existe la repetición o cerradura, la cual habitualmente se indica con el metacaracter ‘*’ y que asociado a una expresión regular, permite que esta se repita cero o mas veces.

Por ejemplo la expresión ‘a*’ que es la que habitualmente se pone como ejemplo, daría como resultado un lenguaje formado por las cadenas de cero o mas caracteres ’a': {ε, ‘a’, ‘aa’, ‘aaa’, …}. Formalmente podrían existir y serían distintos la representación  del conjunto vacío, de la representación (ε) representada anteriormente.

Y ya para finalizar estas ideas básicas, que nos pueden ayudar a entender las expresiones regulares, el hecho de que se pudieran necesitar expresiones mas complejas, hizo necesario que se consideraran algunas operaciones más, o bien restringir las existentes, a partir de esas básicas. Si el metacaracter del (*) permitía que se pudieran definir cero o más repeticiones, se restringía a que existieran una o mas repetición, mediante otro metacaracter como el simbolo de la suma (+). El punto (.) ampliaba el conjunto de operaciones como comodín, concordando con cualquier caracter del alfabeto. Otra operación posible era considerar un intervalo de caracteres, de forma que no fuera necesario enumerarlos todos en una expresión usando el metacaracter de alternancia (|). Se propone habitalmente el guión (-) para ello. Como ejemplo, podeis imaginar la expresión  A-Z equivalente a A|B|…|Z. Y nos queda, la operación de negación (no logico), que también habitualmente se representa mediante el metacaracter del circunflejo (^), aunque en otros caso podemos encontrar también la tilde (~) como equivalente.

Las expresiones regulares pueden ser agrupadas bajo identificadores que usados de forma recursiva permiten describir los lenguajes, formado parte íntima del proceso de analisis léxico de los compiladores, en el reconociento de tokens. Pero ese es un tema demasiado extenso y complejo para abordarlo desde la óptica de estas entradas, siendo mas propio de publicaciones técnicas entre las que personalmente os recomendaría el clásico ”Compiladores, principios, técnicas y herramientas - Isbn 978-970-26-1133-2″  o bien “Construccion de Compiladores de Kenneth C.Louden – Isbn 970-686-299-4″ que han sido y son pasto de mi lectura y mi infinita curiosidad, en los ratos perdidos.

En wikipedia podeis encontrar una referencia al tema http://es.wikipedia.org/wiki/Expresi%C3%B3n_regular.

Necesariamente, al hilo de estos comentarios, al referirnos a las Expresiones Regulares en la entrada, solo las tendríamos en consideración en el contexto de las búsquedas, para localizar o reemplazar términos coincidentes con las expresiones, o bien como elemento que permite validar un texto respecto a una expresión, algo también muy habitual en nuestros programas.

Uso de expresiones regulares en el IDE: optimizar búsquedas en nuestro código.

Deciamos al principio de la entrada, que las expresiones regulares ya existían en el entorno de desarrollo. La búsqueda de términos en nuestro código va a ser algo importante y habitual de nuestro trabajo diario. Son muchas las ocasiones en las que abrimos la ventana de diálogo bien a través del menú de Delphi (Search -> Find / Search -> Find in Files), bien a través de las teclas de atajo rápido (Ctrl + F / Shift + Ctrl + F).

Respecto a versiones anteriores, no han existido cambios salvo los meramente cosmeticos. En Delphi 2007 y versiones anteriores, tanto la búsqueda sencilla como multiple tenían una ventana de diálogo común y mediante un selector, el usuario seleccionaba si quería buscar en la unidad actual o bien en las unidades del proyecto (o cualquiera de las alternativas). Las versiones siguientes, hicieron desaparecer dicha ventana de dialogo para la búsqueda sencilla, quedando embebida en el editor de código a modo de panel, con las distintas opciones que existían.

Y la ventana finalmente, quedaría reservada para la búsqueda en multiples ficheros.

Ahora podemos relacionar las operaciones que hemos visto anteriormente respecto a las expresiones, con la implementación concreta que hace el IDE. Como resultado, la ayuda en linea nos dice que existen disponibles para nosotros los siguientes metacaracteres:

Descripcion
^ Un circunflejo al principio de la expresión encuentra su coincidencia en el principio de linea.
$ El signo del dolar finalizando la expresión hace coincidir con el final de linea. Para entender su uso podeis abrir un nuevo proyecto y escribir como término de busqueda la expresión ”Form.$”. 


En la imagen de ejemplo, veis que tan solo localizó una coincidencia, ya que le pedimos estrictamente que evalue coincidencias que se correspondan con el final de linea, precedidos de los caracteres “form” y un caracter cualquiera. Dicha condición solo la cumple el término resaltado. En la imagen os he marcado con una linea roja varios candidatos (3) de los cuales dos han sido excluidos.

. Un punto representa a cualquier caracter.
* Un asterisco tras un caracter o metacaracter en la expresión, permite encontar cualquier coincidencia en la que aparezca dicho caracter y cero o mas repeticiones del mismo. Una representación muy común para expresar cualquier caracter podría ser la combinación de los metacaracteres “.*”.
+ Un signo de suma resulta similar al visto en el asterisco, salvo que excluye de las coincidencas cualquier cadena con cero repeticiones, es decir, igual al patron de búsqueda.
[ ] El par de metacaracteres [] (corchetes) nos permitirán encontrar todas las coincidencias que combinen los caracteres incluidos en su interior.Creo que se verá mas claro con un ejemplo:

En nuestro ejemplo, la petición era la expresión [orau] y como resultado encontramos 49 coincidencias, que combinan los caracteres incluidos en el corchete.
[^] El metacaracter ^ tiene un significado especial al ser incluido en el interior de los corchetes, pasando a tomar el significado del no lógico, excluyendo de la coincidencia dichos caracteres. En el interior de una expresión puede ayudarnos a excluir resultados. La expresión “Form[^,]” en la imagen siguiente

hace que solo existan 3 coincidencias, de todas las posibles (os las he marcado con una linea de color rojo).
[-] El guión representa al rango de caracteres en el interior de un corchete.
{ } Las llaves permiten agrupar caracteres o expresiones, pudiendose anidar con un máximo de 10 grupos en una expresión sencilla.
\ Una barra invertida previa a cualquier metacaracter, permitiría desactivar el significado especial de éste, de forma que forme parte del alfabeto como cualquier otro caracter. Un ejemplo que me viene a la mente podría ser el uso de la barra invertida (\\) al considerar una ruta de fichero como parte de la expresión.

Aunque en la ayuda no aparece, también podemos usar el separador de alternativas “|” en nuestras busquedas. En la siguiente imagen se busca la expresion “Unit|Form” en la unidad del proyecto y son encontradas 7 coincidencias, entre las que aparecen tanto las coincidentes con Unit como con Form.

En el blog de Malcon Groves, podeis leer en inglés una introducción a este tema. Os aconsejo que le deis una lectura: Searching in Delphi Part 1 : Regular Expressions. La entrada se escribió en los primeros días del 2010, y formaba parte de un conjunto de reseñas de las novedades del IDE.

Yo también creo, como reflexiona Malcon en su entrada, que cobra vital importancia que nuestras búsquedas sean agiles y que encontremos facilmente en nuestro código los términos deseados y en eso, puede ser una herramienta de infinita utilidad saber usar las expresiones regulares. Quizás no tengamos costumbre de usarlas pero la lectura de esta entrada, intenta que reflexionemos sobre el beneficio que podemos encontrar en su uso cotidiano.

Hace unos días encontraba un pequeño problema durante la jornada laboral que dió origen a que me planteara escribir estas dos entradas, abordando las expresiones regulares. El proyecto era amplio, con una gran cantidad de unidades. Ademas existian varios proyectos vinculados a un grupo de proyecto. Y me planteaba la feliz idea de reemplazar un componente en todas las unidades que pudieran aparecer, con el objetivo final de sustituir su uso por otro componente similar ya existente en el proyecto, unificando así ambos en uno solo. Las busquedas en casos así son de vital importancia y hacerlas con agilidad, devolviendo resultados precisos permiten que realicemos la tarea de forma optima. El agrupamiento de resultados no ayudaba demasiado ya que no se ordena alfabeticamente sino que los resultados son agrupados en el mismo orden en el que aparecen las unidades en el proyecto. En mi opinión aquello era un gran error, ya que algunas de las decisiones respecto a los resultados se favorecen si se cuentan con distintos métodos de ordenación y resulta un caos tomarlas sin esa ordenación precisa. De ahí que me viese obligado a estudiar si las expresiones  podían ayudarme, cumpliendo ese comentario que tantas veces hemos compartido y que viene a decir que el blog se alimenta de las necesidades que hemos tenido en el desrrollo de nuestro trabajo. ;-)

En la siguiente parte, vamos a abordar la integración en la RTL de las Expresiones Regulares, que ha sido una de las novedades en XE (ahora ya estamos en condición de estudiarla). Así que os emplazo a que en un breve periodo de tiempo nos volvamos a encontrar en la segunda parte de esté artículo.

Espero que os haya sido de utilidad y os animo a que participeis de forma activa en la Comunidad.

Un abrazo a todos.

Secreto de tres, secreto no es…

abril 5, 2010 en ¿Sabías que...?, ¿Sabías que...? [Delphi], Delphi, Entrada Diario, Noticias, Noticias Delphi

Si tiene algo el refranero es que encierra en un pensamiento breve y conciso, una gran dosis de sabiduría popular y experiencia… También podemos leer:

Secreto de dos, guardado; de más de dos, en la calle echado.

:-)

¿Qué por qué comento esto?

Bueno, veréis… es lo primero que me vino a la cabeza mientras buscaba en Internet información para añadir a una nueva entrada, tal como ésta que estáis leyendo, y vi que ya existían algunas imágenes de la beta de Delphi 2011 colgadas de la Red. Inicialmente creo que estaban en un servidor asiático. Posteriormente las volví a leer en un servidor ruso.

http://www.tdelphiblog.com/2010/03/delphi-2011-fulcrum.html

Y ayer, sin ir mas lejos, volví a encontrármelas en un foro de brasil

http://www.activedelphi.com.br/forum/viewtopic.php?t=54149&start=0&postdays=0&postorder=asc&highlight=&sid=d9eda1c1da6594eb957e8de1b25aa73f

Asimismo, el que aparecieran en los foros españoles, era cuestión de tiempo:

http://www.clubdelphi.com/foros/showthread.php?t=66678

Esta era uno de los tópicos del foro del Club Delphi.

O en el vecino foro de Lazarus.

http://www.lazarus.freepascal.org/index.php?topic=8823.0

En realidad, no aportan demasiada información. Ni siquiera se sabe a ciencia cierta que las imagenes y los comentarios sean verdaderos 100% pero el sentido común nos puede indicar que no hay ninguna razón para pensar que no lo sean. Por cierto, el enlace original asiático desapareció por arte de magia cuando empezó a escampar la noticia…

Bueno… no hay que sudar demasiado… basta poner “Delphi 2011″ en el Google y navegar con paciencia entre sus resultados… Haced vosotros mismos la prueba.

Yo creo que todo esto no ayuda demasiado al equipo de desarrollo de Delphi. Y tampoco, creo yo que sea demasiado bueno que salga a la luz cualquier información indiscriminada antes de hora, con independencia de que pueda ser inofensiva o poco relevante, o al menos nos lo parezca así a nosotros. Entre otras cosas porque siempre va a existir alguien que va a querer llegar un poco mas allá… y se empieza colgando una imagen… y se acaba subiendo en algún servidor perdido del mundo una copia de la beta para que sea descargada por fulanito o menganito, amigos íntimos muy discretos, que a su vez conocen a otro fulanito y a otro menganito, y así hasta que finalmente, en algún punto de la cadena, se quiebra la confianza…

Cada cosa tiene su tiempo, su momento y su oportunidad. Si dijera que pienso otra cosa, mentiría, y creo que  este tipo de noticias no son demasiado positivas. Al igual que otras veces he sido crítico con la actitud de Borland, Codegear o Embarcadero, intento ser justo al valorarlo, y encuentro bastante irresponsable la actitud de la persona o personas que están liberando esta información.

Fuera de lo anecdótico de la noticia (todo el mundo resaltaba su sorpresa de que pudiera verse en el proyecto alguna plataforma distinta de win32), acababa mis pasos como casi siempre hago en el Twitter para rastrear algo que os pudiera ser de interés. Y sí. Creo que he podido encontrar un par de enlaces mucho mas interesantes en mi opinión que la fuga de información incontrolada… :-)

Dos puntos a través del Twitter y otro a través de la suscripción a los canales de video de Embarcadero. Vamos a compartirlos:

El primero de ellos, fue a través de uno de los enlaces que me llevó a un encuentro tecnológico en Bélgica, Trends and future directions in programming languages, celebrado el 31 de Marzo y dirigido por Anders Hejlsberg.

http://channel9.msdn.com/posts/adebruyn/TechDays-2010-Developer-Keynote-by-Anders-Hejlsberg/Default.aspx

El contenido del video es muy interesante y os puede ayudar a entender hacia donde vamos. O digamoslo de otro modo, hacia donde nos quiere llevar Microsoft, que finalmente arrastrará a todos en esa dirección, dicho esto sin ningún matiz peñorativo. Para bien o para mal, parece claro que Microsoft, marcará la evolución de las herramientas de programación y de los lenguajes.

TechDays 2010 Keynote by Anders Hejlsberg: Trends and future directions in programming languages

La conferencia tuvo una duración de algo mas de una hora y quizás los apartados que mas me llamaron la atención son los que se abordan al final de la misma: la programación funcional y la integración del aprovechamiento de los procesos en paralelo.

El segundo punto a comentar sí tiene que ver con Delphi de una forma mas directa. También obtenido a través del Twitter, encontraba el enlace hacia el primer número de una revista holandesa sobre Delphi. El enlace es el siguiente:

http://www.sdn.nl/Delphi/tabid/60/Default.aspx

Y como podéis ver, respaldada por la imagen de Bob Swart, que fue quien facilitó a través del twitter el enlace de descarga

http://www.sdn.nl/LinkClick.aspx?fileticket=sDhRdBRYHis%3d&tabid=58

Pocas páginas y algunas en holandés… :-)    al menos en el primer número. No dudo que el contenido se irá ampliando en lo sucesivo, por lo que interesa conservar el enlace para ir evaluando el interés de su contenido. En principio, el artículo de Cary Jensen, que abre la edición “Creating Editor Key Bindings”, nos introduce en un tema no demasiado conocido por buena parte de programadores de Delphi, mas centrados en el desarrollo de aplicaciones que en complementar el entorno de desarrollo ampliando la funcionalidad del mismo a través del api Open Tools Api (OTA). Esta colección de clases e interfaces nos permiten extender el IDE de Delphi.

Conservaremos el enlace dentro de publicaciones online que hemos abierto en la cabecera de esta página.

Finalmente, el tercer punto me llegó a traves del correo y de la suscripción a los videos de Embarcadero en YouTube

http://www.youtube.com/user/EmbarcaderoTechNet

Durante esta ultima semana se han incluido estos dos videos que figuran mas abajo, de los cuales, el primero puede ser de interés para aquellos compañeros que necesiten conocer de forma rápida, las distintas tecnologías de acceso a datos disponibles desde Delphi, ya que en el video se hace un repaso indicando el estado actual, dado que algunas ya están fuera de uso o no se recomienda su uso. Por otro lado, el video de dbExpress nos muestra como hacer la conexión y que componentes se usan y como se enlazan.

Ambos vídeos han sido editado por Michael Rozlog, Product Manager de Rad Studio.


Database Access Methods in Delphi

http://www.youtube.com/watch?v=_Ayq7cyVI9o


dbExpress Database Access Components in Delphi

http://www.youtube.com/watch?v=dNWerq-Qebo

Nada mas por hoy.

Que paséis un buen día.

Seguir la linea…

marzo 29, 2010 en ¿Sabías que...?, ¿Sabías que...? [Delphi], Delphi, Enlace interesante, Entrada Diario, Noticias, Noticias Delphi, Recordatorio

Espero que encontrarais interesante el artículo de Cary Jensen que compartimos en la entrada anterior y que resalté porque abordaba un tema que, aunque puede no ser crítico, no estaba de más conocerlo.

Shifting TFields in TDataSets Bound to TDBGrids…

Comentábamos que era uno de esos temas en los que se suele caer por accidente, y a veces ni siquiera se llega a ser consciente del problema, pues se tiene que dar la casualidad que al usuario le haya dado por alterar el orden de las columnas en un dbgrid y que justamente se haya escrito codigo que pueda acceder a través de un índice dentro del ClientDataset y que además no existan columnas persistentes… :-)  Quizás son demasiadas casualidades… pero seguro que si algún día se cruzan, será con fatalidad, en una de esas rejillas que tiene que salvar al mundo de una destrucción total:

-Atención sr. presidente… haga doble click en la rejilla para que los misiles destruyan el meteorito…
-Dios mio!!! Esto ha generado una excepción… Estamos todos perdidos…  Se ha bloqueado el sistema…
… (y se hizo el silencio en toda la Tierra… )  :-)

Fuera de lo meramente anecdótico, la idea es seguir trabajando en esa linea e ir seleccionando de cuando en cuando algunas entradas para destacarlas y compartirlas con la comunidad hispana de programadores. Y si es posible, incluso aportar la traducción como ya ha sucedido en dos ocasiones. Aunque eso, os confieso que no resulta tan sencillo, ni disponemos siempre de tiempo suficiente, teniendo en cuenta además, que intentamos hacer las cosas correctamente y solicitamos permiso -previamente- para poder llevar a cabo cualquiera de estas iniciativas. Creo que sería bueno que entre todos, poco a poco fueramos derribando los muros que van aislando a las distintas comunidades, de forma que existieran ventanas y espacios abiertos entre ellas, que las pudieran comunicar y hacer converger.

A veces me pregunto si vamos por buen camino… :-)  Solo hay que seguir las señales.

Hoy he seleccionado a través de la lectura del Twitter, y concretamente del perfil de Malcon Groves, una referencia a la entrada WeakRefence in Delphi – solving circular interface references escrita por Vincent Parrett.  Es una entrada muy interesante, donde se reflexiona acerca de las interfaces y el recuento de referencias, desde un punto de vista enfocado en varios frentes que se interrelacionan: la posibilidad de que nuestra aplicación no libere correctamente la memoria reservada, los posibles errores de acceso o violaciones, que emergerían al acceder desde nuestro código a referencias no validas, y la problemática real que plantea el hecho de tener que evitar las referencias circulares, puesto que éstas, se prohiben expresamente desde nuestro entorno. Vicent Parret utiliza para explicar esta problemática y proponer una posible solución, un ejemplo muy sencillo basado en la relación padre-hijo, aunque entiende que pueda ser resuelta de una forma mas formal desde el mismo compilador:

I still think this is something that could be solved in a better way by the delphi compiler/vcl guys n girls.

Esa posible solución se apoya en la posibilidad de crear una clase TWeakReferencedObject, que le permite evitar la referencia circular y establecer la relación entre las clases padre e hijo. Las últimas lineas de código de su entrada, donde comenta los metodos Get/Set que permiten acceder a la clase padre desde la clase hijo (TChild), lo harían de forma segura.

Ahora mismo no es posible descargar el código completo del ejemplo, puesto que existe un pequeño problema en el fichero zip. Pero en breve, nos ha comentado que lo va a reponer para que pueda ser descargado. Creo que sería interesante darle un vistazo a ese código.

Por cierto, el hecho de que el comentario partiera de Malcon Groves, no es casual ya que, anteriormente, podemos encontrar en su blog varias entradas abordando aspectos relacionados con las interfaces. Concretamente en Casting an Interface Reference to the Implementing Class in Delphi 2010 de fecha 16 deAgosto de 2009, hace una referencia a una de las novedades introducidas en Delphi 2010, relacionadas con las interfaces, que tiene que ver con el operador Is y la posibilidad de que ahora pueda ser utilizado para evaluar si un interface es implementado por una clase especifica:

In Delphi 2010, you can now use the is operator to test to see if an interface type is implemented by a specific class, and if so, cast it to that type and reference any non-interface methods, properties, etc.

Así que si tenéis unos minutos, creo que lo escrito por Malcon Groves puede ser un buen punto de parada para detenerse.

Más cosas en el tintero… (cambiamos de tercio):

Hace unos días hacíamos mención a Intraweb, a raíz del Seminario del día 26 de Febrero. Recordais que hablábamos sobre ello en la entrada Próxima cita el 26 de Febrero haciendo un breve repaso de las sesiones y lo que nos había parecido destacable. En lo que hace referencia a Intraweb, ya tenemos disponibles los ejemplos que se vieron en el seminario y que pueden ser descargados desde la url:

Descarga ejemplos del miniscurso Desmitificando el Intraweb

También es posible acceder al video del curso a través del enlace existente en Embarcadero: Desmitificando el Intraweb

De igual forma, Eliseo González, en uno de sus comentarios anteriores, compartía con nosotros la dirección de descarga de el total de vídeos que componían el seminario del día 26. Comento esto porque fácilmente puede pasar su comentario inadvertido dado que no queda a la vista. Esta es la dirección de Embarcadero en la que podemos encontrarlos:

Delphi Developer Day IV – Vídeos del Seminario

Mas cosas…

Comentaros también que ya está disponible el número 10 de la revista Blaise Magazine, número que requiere la suscripción puesto que ha finalizado el plazo de disponibilidad gratuita para usuarios que hubieran adquirido Delphi 2010 o Rad Studio 2010. Muchos vais a encontrar muy interesante su contenido y por eso lo remarco. Ahora mismo, es una de las pocas publicaciones activas centradas en el Mundo de Delphi y se encuentra traducida a varios idiomas, aunque de momento no a español.

Creo que nada mas por hoy.

Un saludo a todos.

Shifting TFields in TDataSets Bound to TDBGrids…

marzo 24, 2010 en Advertencia, Artículos, ¿Sabías que...?, ¿Sabías que...? [Delphi], Consejo, Delphi, Entrada Diario, traducciones

Esta vez, he seleccionado uno de los artículos del blog de Cary Jensen que me ha parecido especialmente interesante para compartirlo con vosotros. En el artículo, Cary Jensen comenta con sus lectores, un posible bug ocasionado por el comportamiento de los campos persistentes del DataSet (luego se verá en el articulo, comentado y reflexionado por el, que no es tanto un error de código). De cualquier forma, sí me ha parecido interesante pues es algo que debería tenerse en cuenta.

Os explico:  Accidentalmente, se da cuenta que al ser movidas las columnas de una rejilla de datos, una facultad que tiene per se de forma automática al ser creadas, el orden en los campos del dataset es alterado. ¿En que casos? Bueno, esto solo sucede cuando no existen los campos persistentes en el componente TDBGrid y puede generar errores si hemos referenciado llamadas a los campos persistentes del dataset mediante el array TField usando el indice de acceso. Cary, a tenor de lo visto reflexiona en la entrada sobre este punto y las posibles soluciones.

Yo tampoco creo que sea un bug. Aunque particularmente a mi sí me hubiera parecido acertado bloquear la funcionalidad de mover las columnas y solo permitirla en el caso de que hubieran sido creadas, de forma que no hubiera podido existir ese potencial error. Pero bueno… es mi opinión.

Ahh. Como siempre comento, perdonad los posibles errores en la traducción que he intentado que fuera lo menos literal posible.

Vamos a ello:

Shifting TFields in TDataSets Bound to TDBGrids: A Potential Source of Bugs in Your Code

Autor: Cary Jensen – Enero 26, 2010

http://caryjensen.blogspot.com/2010/01/shifting-tfields-in-tdatasets-bound-to.html

He estado trabajando con Delphi desde el principio, con particular énfasis en el desarrollo de bases de datos. Como resultado de ello, no es demasiado frecuente que yo encontrase un comportamiento de los componentes relacionados con los datos que me sorprendiera. Bien. Ha sucedido así en el último mes. Y lo que yo observé  puede ser el origen de errores potencialmente desastrosos, aunque infrecuentes, en un gran numero de aplicaciones de bases de datos con Delphi.

Esto es lo que yo pude observar: Los TFields en un TDataSet abierto, cambiaron de orden en tiempo de ejecución. Especificamente, un TField que estaba originalmente en la posicion cero (DataSet.Fields[0]), en el momento en el que se habia creado el TDataSet, estaba en una posición diferente en el array de campos un pequeño tiempo después. Yo descubrí este comportamiento cuando una excepción fue lanzada como resultado de mi intento, mediante código, de leer el valor entero del campo de tipo TIntegerField que yo habia creado en la primera posición del array de campos de mi TDataSet. Desde el momento en el que yo había creado el TDataSet y la ejecución de mi código, el campo integer habia sido movido de posición.

Lo que habia sucedio no era mágico. Los campos no pudieron cambiar la posición por ellos mismos, ni lo hicieron en algo basado en mi código. Lo que causó que los TFields cambiaran físicamente su posición en el TDataSet fue que el usuario había cambiado el orden de las columnas en el TDBGrid, el cual estaba vinculados al TClientDataSet (a través del componente TDataSource, por supuesto). La habilidad del usuario para cambiar de posición las columnas en un TDBGrid, por cierto, es el comportamiento por defecto en el componente.

Además de ser interesante (He de suponer que una vez que se abrió conjunto de datos, la posición de la “TFields” en la matriz de Campos ya estaba fijada), este comportamiento es la fuente potencial de excepciones intermitentes, el tipo de las que son particularmente difíciles de localizar. Resulta que este comportamiento, que nunca he visto descrito antes, ha existido desde Delphi 1. (En realidad, he observado este efecto en Delphi 7, Delphi 2007 y Delphi 2010. Sin embargo, entiendo que la fuente subyacente de este comportamiento ha existido desde Delphi 1, aunque no lo he confirmado expresamente.)

He creado una aplicación muy sencilla para demostrar este efecto. Consiste en un único formulario en el que existe un TDBGrid, un TClientDataSet y un componente TButton. El ClientDataSet esta enlazado al TDBGrid a traves del TDataSource. En el evento OnCreate del formulario aparece algo como lo siguiente:

procedure TForm1.FormCreate(Sender: TObject);
begin
  with ClientDataSet1.FieldDefs do
  begin
    Clear;
    Add('StartOfWeek', ftDate);
    Add('Label', ftString, 30);
    Add('Count', ftInteger);
    Add('Active', ftBoolean);
  end;
  ClientDataSet1.CreateDataSet;
end;

Button1, está marcado con la etiqueta “Show ClientDataSetStructure” y contiene el siguiente código en el evento OnClick.

procedure TForm1.Button1Click(Sender: TObject);

var
  sl: TStringList;
  i: Integer;
begin
  sl := TStringList.Create;
  try
    sl.Add('The Structure of ' + ClientDataSet1.Name);
    sl.Add('- - - - - - - - - - - - - - - - - ');
    for i := 0 to ClientDataSet1.FieldCount - 1 do
    sl.Add(ClientDataSet1.Fields[i].FieldName);
    ShowMessage(sl.Text);
  finally
    sl.Free;
  end;
end;

Para demostrar el movimiento de los campos, ejecuta la aplicación, haciendo click sobre el botón marcado con la etiqueta Show ClienteDataSet Structure. Tu debería ver lago semejante a lo que muestra la figura 1.

Figure 1

Luego, arrasta algunas columnas del DBGrid y cambia el orden de los campos. Vuelve a hacer click en el botón “Show ClientDataSet Structure”. En ese momento veras algo similar a lo mostrado en la Figura 2.

Figure 2

Lo remarcable de este ejemplo es que la posicion de los TFields en el propiedad Fields del TClientDataSet cambió, de forma que el campo que estaba  en la posición ClientDataSet.Field[0] en un momento determinado no necesariamente está en un momento posterior. Y desafortunadamente, esto no es responsabilidad del TClientDataSet. He realizado la misma prueba con TTables basadas en el bde y TAdoTables basadas en Ado y se obtuvo el mismo efecto.

Contribuyen al resultado de este comportamiento tres factores. Esto son:

  • Un TDBGrid conectado a un DataSet a través de un DataSource
  • El TDBGrid permite al usuario mover las columnas en tiempo de ejcución
  • Las columnas del TDBGrid son dinámicas; significa esto que son creadas por el TDBGrid en ejecución.

Si tú mediante código haces referencia a los campos del DataSet conectados al TDBGrid, y existen las tres condiciones precedentes usando un indice, tu aplicación puede lanzar una excepción, o producir resultados incorrectos, si el usuario mueve una o mas columnas en ese TDBGrid. En la siguiente sección, considerare algunas soluciones para resolver este problema, asi como compartir con Ustedes la razón de ello.

Existen varias soluciones

Existen varias tácticas que puedes usar para eliminar este potencial bug de vuestras aplicaciones. La primera es definir la TColumns de tu TDBGrid usando campos persistentes.

Crear columnas persistentes, puede ser hecho tanto en tiempo de diseño como de ejecución. Para hacerlo en tiempo de diseño, basta añadir las TColumns usando el editor de Columnas. Éste, se muestra haciendo click con el boton derecho del ratón sobre el TDBGrid y seleccionando el Editor de Columnas o bien haciendo click en la ellipsis de la propiedad Columns del TDBGrid en el Inspector de Objetos. Si tu DataSet está Activo, tú puedes hacer click en el botón “Add All Fields” en la toolbar del Editor de columnas.  O bien, añadir uno o mas TColumns y fijar la propiedad FieldName en el Editot de propiedades.

Para crear columnas en tiempo de ejecución, puedes usar los métodos Add o Create de la propiedad Columns del TDBGrid. Puedes fijar los valores de propiedades especificas de las columnas añadidas o creadas.

La segunda solucion,  aunque tiene algunas consecuencias negativas, previene que el usuario mueva las TColumns del TDBGrid. Esto puede ser hecho eliminando el flag dgResizeColumn de la popriedad Options del TDBGrid. Mientras este enfoque es efectivo, elimina opciones del interfaz potencialmente valiosas. Además, eliminando el flag no solo se restringe la opción de reordenar las columnas sino que impide redimensionar el ancho de las columnas. (Para aprender como limitar reordenar las columnas sin eliminar la opción de cambiar el tamaño de la columna ver el articulo de Zarko Gajic How to allow column resize by disable movement (in TDBGrid).

Una tercera solución es evitar referenciar a los TFields del TDataSet basandonos en un índice literal en la propiedad de tipo array Fields( ya que esta es la esencia del problema). En otras palabras, si tu necesitas acceder al campo Count, definido en el codigo de ejemplo que precede, no uses ClientDataSet1.Fields[2].  En la medida que tu conozcas el nombre del campo, puedes usar algo como ClientDataSet1.FieldByName(‘Count’).

Sin embargo existe una gran desventaja en el uso de FieldByName. En concreto, este metodo identifica el campo iterando a traves de la propiedad Fields del TDataSet, buscando  una concidencia basad en el nombre del campo. Desde el momento en que hace esto cada vez que se invoca FieldByName, deberias evitarlo en situaciones donde el campo necesita ser referenciado muchas veces, como sucede en un bucle que recorre un TDataSet muy extenso, con muchos campos.

Si tu necesitas apuntar al campo repetidamente (y en un gran numero de veces) considera el uso de algo como el siguiente fragmento de código:

var
CountField: TIntegerField;
Sum: Integer;
begin
 Sum := 0;
  CountField := TIntegerField(ClientDataSet1.FieldByName('Count'));
  ClientDataSet1.DisableControls; //assuming we're attached to a DBGrid
  try
    ClientDataSet1.First;
    while not ClientDataSet1.EOF do
    begin
      Sum := Sum + CountField.AsInteger;
      ClientDataSet1.Next;
    end;
  finally
    ClientDataSet1.EnableControls;
  end;
end;

La cuarta solucion es el uso del método FieldByNumber de la propiedad Fields del TDataSet. Si ya tienes código escrito que usa un indice para el array Fields, y trabaja correctamente, siempre y cuando el usuario no mueva las columnas del TDBGrid, esta es otra solucion. Cambia tu codigo para usar FieldByNumber.

Hay dos aspectos interesantes para el uso de FieldByNumber. Primero tu debes cualificar su referencia con la propiedad Fields de tu DataSet. Segundo, al contrario del array Fields, que es basado en indice cero, FieldByNumber  se inicia en 1 para indicar la posición del campo que tu quieres referenciar.

La siguiente es una versión actualizada del manejador del evento OnClick de Button1, mostrado anteriormente, que usa el método FieldByNumber.

procedure TForm1.Button1Click(Sender: TObject);

var
  sl: TStringList;
  i: Integer;
begin
  sl := TStringList.Create;
  try
    sl.Add('The Structure of ' + ClientDataSet1.Name +
       ' using FieldByNumber');
    sl.Add('- - - - - - - - - - - - - - - - - ');
    for i := 0 to ClientDataSet1.FieldCount - 1 do
    sl.Add(ClientDataSet1.Fields.FieldByNumber(i + 1).FieldName);
    ShowMessage(sl.Text);
  finally
    sl.Free;
  end;
end;

Para el ejemplo propuesto, el código produce el siguiente resultado, sin considerar la posición de las columnas en la rejilla asociada. Esto se puede ver en la Figura 3

Figura 3

Hay una quinta solución, pero solo está disponible cuando tu TDataSet es de la clase TClientDataSet, como el que existe en mi ejemplo. En esas situaciones, tu puedes crear un clon del TClientDataSet original, y mantener la estructura original. En consecuencia, cualquiera que sea el campo que originalmente aparezca en la posicion zero, seguira estando en la misma posición, con independencia de que haya podido hacer el usuario al TDBGrid que muestra los datos del TClientDataSet.

Notar que no estoy sugiriendo que  debas referenciar los campos TFields del TDataSet usando literales enteros. Personalmente, el uso de un variable de tipo TField, que se inicializa a través de una llamada a FieldByName es más legible e inmune a los cambios en el orden físico de la estructura de la tabla(¡aunque no sea inmune a los cambios en los nombres de tus campos!) .

Para terminar

Hay un par de puntos finales que quisiera hacer. Primero, la actual estructura subyacente no es afectada. Especificamente, si despues de cambiar el orden de las TColumns en un TDBGrid, llamas la método SaveToFile de la clase TClientDataSet enlazado a ese TDBGrid, la estructura guardada es la original (la verdadera estructura interna). De forma similar, si tu asignas la propiedad Data de un TClientDataSet a otro, el TClientDataSet destino tambien muestra la estructura verdadera (lo cual es similar al efecto observado cuando un origen de datos TClientDataSet es clonado).

De igual forma, cambios en el orden de las columnas de TDBGrids enlazados a otros probados TDataSets, incluyndo TTable y ADOTable, no afectna a la estructura interna de las tablas. Por ejemplo, un TTable que muestra datos desde la tabla de ejemplo de Paradox customer.db que viene con Delphi no cambia esta estructura de la tabla en disco (ni lo esperarias).

El segundo punto es que esto no es un bug en cualquiera de la clases TDataSet o TDBGrid (o TColumn o TField). Es asi como esas clases han sido diseñadas para trabajar. Y aunque este comportamiento introduce errores en tus aplicaciones, esto es porque nosotros no hemos cuidado ésto hasta el momento. Y, tu ahora conoces como se comportan tan bien como para prevenir que causen excepciones en tus aplicaciones con Delphi.

El punto final viene a nosotros por el usuario Sertac Akyuz desde StackOverflow, quien respondió a la pregunta acerca de este comportamiento que yo publiqué en ese sitio Web. Yo había revisado las fuentes tanto para la clase TDataSet como para la clase TDBGrid y no pude localizar el origen del mismo. Sertac escribió que este comportamiento es escontrado actualmente en las clases TColumns y TFields. Especificamente, cuando cambia la posicion de la columna de una TColumn dinámica (no persistente), fruto de una llamada al metodo que fija la propiedad Index de TField, lo cual afecta a la posición de ese campo en la propiedad Fields del TDataSet.

Ahora tu sabes que este potencial problema existe, bajo que condiciones puede emerger, también como sus efectos, deberias ahora echar un vistazo a tus aplicaciones para ver si tienes TDBGris con TColumns no persistentes que el usuario pueda mover en tiempo de ejecución. Si además, referencias las campos TFields con esas TColumns usando indices literales a la propiedad Fields del TDataSet, puedes eliminar errores potenciales resultado de apuntar a un campo erroneo en tiempo de ejecución usando una de las soluciones que yo he apuntando anteriormente en este artículo.

Copyright (C) 2010 Cary Jensen. All Rights Reserved

Channel E (Embarcadero) – Canal de vídeos y novedades.

febrero 3, 2010 en ¿Sabías que...?, Entrada Diario, Eventos, Videos

Canal de videos de Embarcadero

Canal de videos de Embarcadero

Esta imagén que veis, se corresponde con el canal de videos que se ha hecho disponible en http://channel-e.embarcadero.com/

La creación del canal era comentaba por David Intersimone en el boletín del mes de Enero (Embarcadero Developer Network (EDN) newsletter – January 2010), que se recibió hace un par de días. Por si no lo conocéis, es un correo que se envía periódicamente a una lista de suscriptores, que me imagino se corresponde con los usuarios registrados. Y ese correo se detalla un resumen breve de las actividades de la empresa, de los seminarios previstos o de las novedades.

En mi caso, yo buscaba esta tarde dicho boletín por confirmar si existía en él alguna referencia a un próximo evento que afecta a la comunidad hispana, comentario que ha sido recogido en el twitter por Andreano Lanusse. Nos comentaba literalmente:

Comunidad de habla hispana, prepárense para el Delphi Developer Days IV de Embarcadero en Español – en breve más información…

Pero no he encontrado ninguna referencia por lo que supongo que en próximos días se hará algún anuncio de la fecha prevista para el evento. En lo que respecta al boletín de este mes, creo que se merece resaltar la creación del canal de vídeos (comentada lineas mas arriba) que nos va a facilitar tener una zona en el que se agrupe el contenido audiovisual, con independencia de que exista en dicha página también una referencia también a la “blogosfera” de embarcadero y a las noticias de Twitter.

Asimismo, parece que existe un cierto movimiento hacia la publicidad de las aplicaciones hechas con las herramientas de embarcadero, creandose una especie de portafolio

http://www.embarcadero.com/application-showcase

y promoviendo varias encuestas donde animan a los desarrolladores y a las empresas a hacer publicos sus proyectos, aplicaciones y  webs construidas con ellas. Estas son por ejemplo las de Delphi y Delphi Prism.

Delphi - http://www.surveymonkey.com/s.aspx?sm=BNcBkVCUCEDharLhLrmCyg_3d_3d

Delphi Prism – http://www.surveymonkey.com/s.aspx?sm=lrvDFN5KEZeQovcluehCCw_3d_3d

No se si olvido algo… ummmm…   ~~:-/

Vale. Ya me ha venido a la cabeza: Tenía agregada a los marcadores del navegador una url que me ha parecido muy interesante y que la había guardado con la idea de comentarla en alguna de las entradas.

Entropy Overload de Barry Kelly.

Si quereis que os diga la verdad, la mayoría de las webs que se van cruzando en el camino son fruto de la casualidad y en este caso, simplemente porque buscaba ampliar conocimientos  sobre el recolector de basura de punto net, llegando a la entrada http://blog.barrkel.com/2009/12/commonly-confused-tidbits-re-net.html, donde se aborda el tema. También me ha parecido interesante otra donde habla del soporte RTTI en Delphi 2010. Así que cuesta poco apuntar la dirección por si en algún momento posterior deseamos volver con mas tiempo (como siempre hacemos la dejamos añadida en la barra lateral).

Nada mas por hoy. Me despido con la cita que marca hoy mi agenda:

:-)

“El hombre que no sabe sonreír, no debe abrir tienda…” (Proverbio chino)

Que tengáis un buen día.