Ya les comenté en el post anterior que hay algunos errores que se les manifiestan a muchos usuarios de ZinjaI, y que entonces iba a comentarlos aquí, con sus causas y pseudo-soluciones para facilitar un poco las cosas. Decidí empezar por dos problemas particulares (de los cuales creo que ZinjaI no tiene culpa alguna), porque son de los que más me han consultado a mi correo personal. El que presento hoy tiene que ver con esos infames comerecursos que son los antivirus, y se manifiesta de esta forma: cada vez que desde ZinjaI se quiere compilar y ejecutar un programa, la compilación finaliza con éxito (suponiendo que el código era correcto), pero en la ventana de ejecución sale algo como "Error al crear proceso: C:\booga\dooga\algun_programa.exe".
lunes, 18 de agosto de 2014
jueves, 14 de agosto de 2014
Preguntas frecuentes: "No hay disco en la unidad"
El título de este post muestra parte de un mensaje de error que aparece frecuentemente en PCs con Windows tras actualizar ZinjaI a su última versión. ZinjaI está lleno errores, algunos que conozco, seguramente cientos que todavía no noté, pero este en particular, y otro que comentaré en el próximo post, no son errores propios. Son "problemas" de Windows (o sus drivers) uno, y del antivirus que lo acompaña el otro. Me cansé de responder consultas a mi correo personal por estos problemas una y otra vez, así que lo publico acá para que cualquiera lo encuentre fácil, y para redireccionar a los próximos que pregunten.
jueves, 31 de julio de 2014
Entendiendo la tabla de inspecciones (parte 1)
La tabla de inspecciones de ZinjaI es esa grilla que aparece abajo a la izquierda al iniciar una depuración, donde podemos escribir nombres de variables y otras expresiones C++ para ver cuánto valen en cada pausa de la ejecución. Hay algunos detalles de interfaz conviene conocer como usuario de ZinjaI, y hay otros sobre la implementación interna de la misma y su comunicación con gdb que se podrían ignorar tranquilamente, pero igual resultan interesantes. Y es que desde hace un buen tiempo venía pensando en reescribir en ZinjaI todo el código relacionado a esta tabla y al manejo de inspecciones en general. Ahora que la reescritura ha avanzado bastante y las cosas se van definiendo, aprovecho para contarles de qué se trata y documentar un poco algunos trucos que se usan por debajo.
martes, 24 de junio de 2014
Sobre señales y volcado de datos
Creo que para la mayoría de los programadores, la depuración es la etapa que más tiempo consume en un desarrollo. A mi me gusta modificar un poco la regla del noventa-noventa para decir que el segundo 90% corresponde a la depuración. Depurar implica probar un programa para detectar errores, identificar sus causas, plantear posibles soluciones, y aplicar el mismo proceso recursivamente sobre estas soluciones, hasta que la recursión se corte porque ya [creemos que] no hay errores.
La parte de identificar la causa puede ser muy tediosa cuando llegar al punto en que se produce o manifiesta el error lleva bastante tiempo de ejecución. Porque el procesamiento previo es costoso, porque hay que cargar muchos datos, porque depende de acciones manuales del usuario, porque no sabemos bien cuándo va a manifestarse, por lo que sea. Y a veces hay que repetirlo y repetirlo para ir acotando el problema, porque cuando vemos el error, nos damos cuenta de que nos falta información, de que tenemos que modificar un poco el código para que genere y/o muestre más resultados intermedios y volver a probar. Hoy les comento un truco que, utilizando señales, permite generar en cualquier momento, desde cualquier punto de la ejecución, un volcado de datos ad-hoc y arbitrario hacia un archivo, para analizar el estado del programa.
La parte de identificar la causa puede ser muy tediosa cuando llegar al punto en que se produce o manifiesta el error lleva bastante tiempo de ejecución. Porque el procesamiento previo es costoso, porque hay que cargar muchos datos, porque depende de acciones manuales del usuario, porque no sabemos bien cuándo va a manifestarse, por lo que sea. Y a veces hay que repetirlo y repetirlo para ir acotando el problema, porque cuando vemos el error, nos damos cuenta de que nos falta información, de que tenemos que modificar un poco el código para que genere y/o muestre más resultados intermedios y volver a probar. Hoy les comento un truco que, utilizando señales, permite generar en cualquier momento, desde cualquier punto de la ejecución, un volcado de datos ad-hoc y arbitrario hacia un archivo, para analizar el estado del programa.
martes, 17 de junio de 2014
Corrigiendo un ejecutable sin reiniciar la depuración
En este post les vengo a mostrar una funcionalidad nueva en ZinjaI, que verán en la próxima versión (a publicarse dentro de pocos días), y que bien presentada parece mágica, aunque está lejos de serlo. Con el ejemplo adecuado, puedo hacer que se parezca al maravilloso Edit & Continue de Visual Studio (la funcionalidad que realmente me maravilla y envidio de ese IDE que tan poco conozco). Consiste en la posibilidad de modificar el ejecutable mientras se está ejecutando, durante una pausa en una depuración, alterando el código fuente, recompilando, y continuando luego de la pausa desde el mismo punto con el binario nuevo como si nada. Estoy a años luz de ofrecer algo como eso de verdad, pero puedo hacer algunos trucos simples para emularlo en casos muy muy particulares. Vean el video y luego sigan leyendo.
miércoles, 14 de mayo de 2014
Cómo [no] ayudar al compilador
Siempre les digo a mis alumnos: "el compilador es más vivo que todos nosotros juntos", y la experiencia me ha demostrado que es una buena máxima para respetar a la hora de programar. Me refiero a esos momentos donde programamos algo de cierto modo que no es precisamente el más prolijo ni el más simple, pero imaginamos que hacerlo como dicen los libros sería agregar algún tipo de sobrecarga evitable. Y esto se debe a que imaginamos mal o desconocemos qué va a hacer con eso el compilador.
Por dar un ejemplo simple, he usado mil veces macros de preprocesador (#define func(x) bla...bla) en lugar de funciones para evitar la sobrecarga que significa invocar a una función. Está claro que a nivel ensamblador la llamada a una función, por simple que sea ésta, implica varias instrucciones adicionales (preparar el stack, crear variables locales, pasar los argumentos, recibir el resultado, etc). Pero debería estar igual de claro que considerar eso al codificar es un gran gran error. Es un problema que un buen compilador sabrá resolver mucho mejor que nosotros. En este post quiero dejar algunos tips sobre cosas como estas no hay que hacer y otras cosas sí, si queremos que lo que hacemos de verdad le sirva al compilador para generar un mejor ejecutable.
Por dar un ejemplo simple, he usado mil veces macros de preprocesador (#define func(x) bla...bla) en lugar de funciones para evitar la sobrecarga que significa invocar a una función. Está claro que a nivel ensamblador la llamada a una función, por simple que sea ésta, implica varias instrucciones adicionales (preparar el stack, crear variables locales, pasar los argumentos, recibir el resultado, etc). Pero debería estar igual de claro que considerar eso al codificar es un gran gran error. Es un problema que un buen compilador sabrá resolver mucho mejor que nosotros. En este post quiero dejar algunos tips sobre cosas como estas no hay que hacer y otras cosas sí, si queremos que lo que hacemos de verdad le sirva al compilador para generar un mejor ejecutable.
lunes, 5 de mayo de 2014
Interesante problema de Estructuras de Datos
En varios casos en ZinjaI tengo datos que necesito utilizar en dos contextos diferentes, requiriendo en uno el conjunto completo, y en otro solo una parte. Tomemos por ejemplo la lista de breakpoints de un proyecto. Mientras se edita un archivo fuente, la mayoría de las operaciones con breakpoints (agregar, quitar, definir propiedades, etc) se hará sobre los de ese fuente. Además, al guardar esta información en el proyecto, los breakpoints de un fuente se guardan asociados al mismo. Sin embargo, una lista de breakpoints por fuente no siempre es lo mejor porque muchas operaciones en el depurador (a nivel gdb) se harán sobre la lista completa. Por ejemplo, al inicializar la depuración, se deben setear todos los breakpoints en gdb antes de ejecutar, sin importar de dónde provengan. La misma idea aplica a varias otras cosas, como por ejemplo los archivos del proyecto (que están agrupados por categorías) o próximamente las inspecciones (que están asociadas a distintas ventanas/paneles de la interfaz).
Entonces, hace poco me armé un par de clases para representar dos contenedores que operen sobre los mismos elementos. Es decir, habrá un contenedor para el conjunto global, y otro para los subconjuntos parciales. A nivel algoritmos y estructuras de datos creo que es un ejercicio interesante, y por eso vengo a(documentarlo) comentarlo en este post.
Entonces, hace poco me armé un par de clases para representar dos contenedores que operen sobre los mismos elementos. Es decir, habrá un contenedor para el conjunto global, y otro para los subconjuntos parciales. A nivel algoritmos y estructuras de datos creo que es un ejercicio interesante, y por eso vengo a
lunes, 14 de abril de 2014
Aplicaciones visuales con ZinjaI
Después de algunos años ya de utilizar ZinjaI en combinación con wxFormBuilder, creo que la integración de ambas herramientas ha quedado bastante aceitada. Para quien no lo conozca, wxFormBuilder es una programa que permite "dibujar" interfaces (digamos ventanas para nuestros programas) de forma visual (como si fuera Visual Basic, o Borland Builder), y luego generar automáticamente el código fuente C++ (o Python) que produce esas interfaces para usarlas en nuestros proyectos. Por un lado nos automatiza un poco una tarea a veces tediosa y repetitiva, y por otro nos ahorra escribir mucho código y consecuentemente también investigar la forma de utilizar la biblioteca de componentes gráficos.
Desde un proyecto de ZinjaI, podemos aprovechar esto, y ZinjaI está particularmente preparado para simplificar mucho la interacción entre ambas partes, y estas características de ZinjaI han mejorado bastante en las últimas versiones. Por eso en este post voy a resumir qué se puede hacer, en líneas generales cómo funciona a nivel del código (y aquí va otro uso interesante del polimorfismo) y los pasos básicos para empezar a aprovecharlo. Espero con esto mostrar lo simple y rápido que es hacer GUIs con esta combinación de herramientas.
Desde un proyecto de ZinjaI, podemos aprovechar esto, y ZinjaI está particularmente preparado para simplificar mucho la interacción entre ambas partes, y estas características de ZinjaI han mejorado bastante en las últimas versiones. Por eso en este post voy a resumir qué se puede hacer, en líneas generales cómo funciona a nivel del código (y aquí va otro uso interesante del polimorfismo) y los pasos básicos para empezar a aprovecharlo. Espero con esto mostrar lo simple y rápido que es hacer GUIs con esta combinación de herramientas.
lunes, 7 de abril de 2014
Un "feature" para ZinjaI por cortesía del servidor X
En el mundo GNU/Linux hay desde hace un buen tiempo un revuelo importante de noticias relacionadas a los servidores gráficos. El famoso servidor X que utilizamos actualmente (Xorg) está viejo, muy viejo, tiene cerca de 30 años. Todo parecía indicar que el relativamente reciente Wayland iba a ser el gran reemplazo hasta que Cannonical quiso hacer la suya y metió al más reciente Mir en la discusión. Sea cual sea el reemplazo (personalmente espero que triunfe Wayland, y creo que así será), el X tenía algunas características muy útiles que los nuevos no tendrán. Y está bien que no las tengan, porque no siguen la misma filosofía, porque están diseñados en el 2000 y no en los 80. Pero hay una muy discutida que voy a extrañar, porque la uso para programar con ZinjaI. Es la posibilidad de ejecutar un programa en una PC y verlo en el servidor gráfico de otra, el infame X remoto. Les cuento hoy de qué se trata y cómo me resulta útil, antes de que migremos a Wayland y tengamos que buscar otra opción.
viernes, 28 de marzo de 2014
Sobre el futuro a mediano plazo de ZinjaI
El fin de semana pasado publiqué una versión nueva de ZinjaI con muchas mejoras, aunque la mayoría no son fácilmente visibles. Hay pequeños detalles por aquí y por allá en la interfaz, hay mejoras en casos particulares para el autocompletado, hay algún que otro cambio en la configuración de proyecto para simplificar algunos nuevos complementos, etc. Aunque también hay cosas que se ven, como la nueva ventana de ayuda sobre C++ que permite explorar offline el contenido ofrecido por cppreference (con licencia CC, instalable como complemento); o el nuevo cuadro de configuración para la integración de proyectos con wxFormBuilder (de lo que hablaré en breve en otro post). Pero el tópico de hoy apunta a comentar qué grandes cambios (visibles o no) estoy pensando a futuro. Algunos para la próxima versión, otros tal vez tarden un poco más en llegar.
jueves, 13 de marzo de 2014
El autocompletado y yo (capítulo 2)
Ya comenté hace mucho cómo funcionaba el sistema de autocompletado en ZinjaI, y cuales eran sus limitaciones. Básicamente, por un lado tengo a cbrowser, una herramienta que analiza los fuentes y me dice qué cosas se definen. Su parseo es mucho más rápido que el de un compilador, ya que no usa toda la información disponible, pero aún así no es tan rápido como para aplicar en tiempo real. Por eso solo se aplica cada vez que se guarda un archivo fuente, completando con su información el árbol de símbolos. Luego, como el autocompletado es necesario mientras estamos editando un fuente, tiene que haber otro mecanismo en tiempo real para compensar la falta de actualización de esa información. Y además, mientras lo editamos, el código no es válido, está a mitad escribir, y en ese caso el análisis de cbrowser tampoco funcionaría. Entonces tengo un mecanismo alternativo que analiza un fuente abierto, mirando solo ese fuente (y solo cerca de donde estemos editando), y aplicando una heurística propia y poco fiable, pero muy rápida y tolerante a errores de sintaxis. Esencialmente se encarga de dos cosas: tratar de averiguar de qué tipo es una variable mirando si hay algo que pueda ser su definición (sino se buscará en el árbol de símbolos), y averiguar qué representa hasta el momento una expresión a mitad escribir.
Hace un tiempo que me decidí a reescribir este último mecanismo. Lo quise reescribir porque estaba fragmentado en diferentes lugares de ZinjaI y entonces había algunas funcionalidades repetidas, y otras difíciles de reutilizar. Mi idea era mejorar el diseño para agregar algunas mejoras muy útiles, y de paso tratar de que todo se analice con el mismo código para simplificar el mantenimiento y acotar los problemas. En este artículo entonces voy a describir los problemas a los que me enfrento al hacer esto, y qué hay de nuevo para la próxima versión de ZinjaI.
Hace un tiempo que me decidí a reescribir este último mecanismo. Lo quise reescribir porque estaba fragmentado en diferentes lugares de ZinjaI y entonces había algunas funcionalidades repetidas, y otras difíciles de reutilizar. Mi idea era mejorar el diseño para agregar algunas mejoras muy útiles, y de paso tratar de que todo se analice con el mismo código para simplificar el mantenimiento y acotar los problemas. En este artículo entonces voy a describir los problemas a los que me enfrento al hacer esto, y qué hay de nuevo para la próxima versión de ZinjaI.
lunes, 10 de marzo de 2014
El programador es un pequeño Dios
Empieza una vez más el cursado en "mi" Universidad, y como docente de una de las comisiones de teoría de la materia "Fundamentos de Programación" tengo la enorme responsabilidad de presentarles la programación por primera vez a muchos jóvenes ingresantes. Es una oportunidad única para que empiecen motivados y con el pie derecho, para que lo vean como algo atrapante y divertido, y no como una materia más. Y es en este contexto, donde cada año al preparar esos primeros 15 minutos de la primer clase, divago sobre la naturaleza de la programación, como lo voy a hacer en este post. Pero antes de seguir leyendo, estén advertidos de que será una ensalada de cosas muy subjetivas relacionadas de formas cuestionables.
Miles de artículos se han escrito debatiendo acerca de la naturaleza de la programación, ¿arte o ciencia? Si me preguntan a mi, es ambas cosas, pero primero digo arte, porque lo de ciencia lo doy por obvio, mientras que lo de arte es lo más discutido. De todas, formas, no es esta pregunta el eje de este post, sino que pretendo volcar en algunas lineas una visión general y motivadora de la parte que más disfruto de esta maravillosa actividad, la visión que me gustaría transmitir a mis alumnos y compañeros para alentarlos a disfrutar de los desafíos como yo lo hice cuando estaba aprendiendo, y como lo sigo haciendo en la mayoría de los casos.
Miles de artículos se han escrito debatiendo acerca de la naturaleza de la programación, ¿arte o ciencia? Si me preguntan a mi, es ambas cosas, pero primero digo arte, porque lo de ciencia lo doy por obvio, mientras que lo de arte es lo más discutido. De todas, formas, no es esta pregunta el eje de este post, sino que pretendo volcar en algunas lineas una visión general y motivadora de la parte que más disfruto de esta maravillosa actividad, la visión que me gustaría transmitir a mis alumnos y compañeros para alentarlos a disfrutar de los desafíos como yo lo hice cuando estaba aprendiendo, y como lo sigo haciendo en la mayoría de los casos.
viernes, 28 de febrero de 2014
Excusas para no documentar un código
En un proyecto de software tenemos dos tipos básicos de documentación. Por un lado está la documentación para el usuario final, para que aprenda a utilizarlo, como los manuales de ayuda o las referencias, mientras que por otro lado está la documentación sobre el desarrollo del mismo, como los diagramas de clases, casos de uso, o los comentarios en el código por ejemplo. Quiero hablar particularmente de los últimos, de los comentarios en el código (lo que se conoce como documentación interna) porque es algo que creo que a la mayoría no nos simpatiza mucho tener que hacer, pero que tampoco podemos delegar. El manual de usuario, por ejemplo, sí lo podría hacer por otra persona que no sea la que codificó el programa. Pero la documentación interna en general es responsabilidad directa del programador.
Como ya dije, es algo que consume tiempo y ganas, y por eso solemos inventar mil excusas para no hacerlo (o si es un proyecto individual, directamente no lo hacemos, sin tener que rendirle excusas a nadie). Pero a la larga, las consecuencias de una mala documentación terminan costando todavía más tiempo y paciencia (mucho más) de lo que habría costado hacerlo bien en su momento. Yo lo aprendí por las malas, mis códigos viejos son claras evidencias de ello, y por eso ahora vengo a refutar las excusas más comunes que nos ponemos para saltearnos ese trabajo.
Como ya dije, es algo que consume tiempo y ganas, y por eso solemos inventar mil excusas para no hacerlo (o si es un proyecto individual, directamente no lo hacemos, sin tener que rendirle excusas a nadie). Pero a la larga, las consecuencias de una mala documentación terminan costando todavía más tiempo y paciencia (mucho más) de lo que habría costado hacerlo bien en su momento. Yo lo aprendí por las malas, mis códigos viejos son claras evidencias de ello, y por eso ahora vengo a refutar las excusas más comunes que nos ponemos para saltearnos ese trabajo.
jueves, 13 de febrero de 2014
Polimorfismo en psexport
Psexport es uno de los módulos de PSeInt, el que se encarga de traducir un algoritmo en pseudocódigo a lenguajes de programación reales como C, C++, Java, PHP, etc. En realidad hace la mitad del trabajo. Traducir implica primero entender qué es lo que está escrito en un lenguaje, para luego ver cómo escribirlo en el otro. La primer parte la hace el mismísimo intérprete, generando un archivo intermedio "premasticado" para que psexport lea más fácilmente y dedique sus mayores esfuerzos a ver cómo sería mejor escribirlo en ese otro lenguaje. Inicialemente, ese otro lenguaje era solo C++, pero recientemente se añadieron unos cuantos más. La orientación a objetos y particularmente el polimorfismo hicieron que pueda programar todas esas nuevas traducciones con muy poco esfuerzo. Así que en este post les voy a mostrar un ejemplo del tan valioso y no siempre bien ponderado polimorfismo.
viernes, 7 de febrero de 2014
Polimorfismo en C++
El uso del polimorfismo en C++ es uno de los temas que más complicaciones les trae a los estudiantes cuando están haciendo sus primeras armas en C++ y Programación Orientada a Objetos. Aclaro que estoy hablando de clases abstractas y métodos virtuales, porque algunos materiales cuentan la sobrecarga como un tipo de polimorfismo. Tal vez se deba a que para utilizarlo hay que tener claras las ideas de la POO y el diseño de clases por un lado (algo muy difícil si se tiene poca experiencia), y por otro lado los conceptos del manejo de memoria en C++, ya que involucra punteros y conversiones implícitas de tipo. Es decir, ni el diseño ni la sintaxis son triviales. Entonces es lógico que les resulte complejo. El problema es que culpa de esto, le esquivan todo lo posible, y terminan no utilizándolo.
Se puede hacer todo tipo de cosas en C++ sin utilizar polimorfismo, es posible evitarlo, o emularlo. Pero en muchísimos casos, hacerlo de esa manera implica más código, clases más complejas, implementaciones más rebuscadas, más dependencias entre objetos, o el uso de otros trucos tanto o más complicados que el mismo polimorfismo que estaban tratando de evitar. Voy a comentar en este artículo rápidamente de qué se trata, cuales son los mecanismos del compilador que hay por detrás, y qué usos le podemos dar, para que sirva de introducción a otros artículos donde comentaré casos particulares y de interés en PSeInt y en ZinjaI.
Se puede hacer todo tipo de cosas en C++ sin utilizar polimorfismo, es posible evitarlo, o emularlo. Pero en muchísimos casos, hacerlo de esa manera implica más código, clases más complejas, implementaciones más rebuscadas, más dependencias entre objetos, o el uso de otros trucos tanto o más complicados que el mismo polimorfismo que estaban tratando de evitar. Voy a comentar en este artículo rápidamente de qué se trata, cuales son los mecanismos del compilador que hay por detrás, y qué usos le podemos dar, para que sirva de introducción a otros artículos donde comentaré casos particulares y de interés en PSeInt y en ZinjaI.
Suscribirse a:
Entradas (Atom)