Usando Iron, un web framework para Rust

Actualmente, si quiéres hacer una aplicación web con Rust, te recomiendo Rocket, es mucho más sencillo de usar, más potente, más rápido y tiene más usuarios.

Rust cada día atrae a más desarrolladores. Es eficiente y es robusto. Mozilla ha sido la principal impulsora de este lenguaje para ser usado en entornos tan complejos como el propio Firefox.

Hoy vamos a introducirnos en el mundo del desarrollo web con Rust. Cuando la gente oye desarrollo web normalmente se piensa en lenguajes como PHP, Python, Ruby o JavaScript. Estos son lenguajes con los que es rápido desarrollar algo, aunque son mucho menos eficientes y es más fácil cometer errores debido a que son interpretados directamente. Un paso por encima tenemos a Java y C#, que cubren en parte las carencias de los otros lenguajes mencionados. Ha llegado la hora de hablar de Rust. Si bien es cierto que hay web frameworks en C++, nunca han sido muy populares. ¿Será Rust la opción que finalmente nos permita tener aplicaciones web con una eficiencia nativa?

Existen varios web frameworks en Rust, para este tutorial vamos a usar Iron, el más popular según Crates.io. Quizá te interese echar un vistazo también a Rocket, mi preferido.

ironframework

Crear proyecto e instalar Iron

Lo primero que hay que hacer es crear un nuevo proyecto en Rust, lo hacemos gracias a Cargo.

Ahora editamos el fichero Cargo.toml para añadir las dependencias que vamos a usar.

Ahora obtenemos las dependencias especificadas con Cargo.

Hola Mundo con Iron

Vamos a empezar a programar en Rust. Vamos a hacer una simple aplicación que devuelva “Hola Rustáceos” por HTTP.

Editamos el archivo src/main.rs

holarustaceos

Usando router para el enrutamiento

Hemos hecho un pequeño servidor HTTP con Iron. Pero nos falta algo, que sea capaz de manejar rutas. Que miweb.com/hola no sea lo mismo que miweb.com/adios. Iron por defecto no trae enrutador, pero es muy habitual usar Router, que ya hemos instalado antes por conveniencia.

getiron

Archivos estáticos

Para gestionar los ficheros estáticos vamos a usar staticfile y mount, otras dos librerías para Iron.

ironstaticfile

 

Hemos dado nuestros primeros pasos en Iron, un web framework para Rust. Iron es completamente modular y soporta muchas más cosas que aquí no hemos visto. Gran parte de su funcionalidad se implementa a través de middleware, como en otros web frameworks populares.

Redox, el sistema operativo escrito en Rust

Hoy voy a hablar de Redox, un sistema operativo relativamente nuevo, escrito totalmente en Rust. Redox sigue la filosofía UNIX y la mayor parte del sistema es accesible a través del sistema de archivos. En Redox esta función la cumplen las URL. Además, es un sistema operativo seguro, una de las principales características de Rust. En Redox además todas las aplicaciones corren en modo sandbox.

Compilar Redox

Redox se distribuye únicamente a través del código fuente. En el futuro habrá imágenes ISO. Funciona en x86 de 32 bits y se está trabajando en el soporte x86_64 de 64 bits. En Debian/Ubuntu hay que seguir estas instrucciones.

Una vez haya terminado podemos ejecutar Redox en una máquina virtual. Yo voy a usar QEMU.

Un vistazo rápido

Redox1 Redox2 Redox3

Entramos directamente al escritorio gráfico, no ha hecho falta seleccionar nada. Redox es un sistema operativo diseñado con la interfaz ya en mente, no como los sistemas UNIX donde el sistema gráfico viene de terceras partes (X11, Quartz, DirectFB, Wayland, Mir, …).

Aplicaciones

Redox dispone de dos editores, el editor básico (que como vemos, el archivo que abre por defecto es none:/, el concepto de todo es una URL es básico en Redox) y Sodium, un editor más avanzado (tipo Vi o Emacs). Tenemos un explorador de archivos, un terminal de Lua, un terminal de comandos, un visor de imágenes y una aplicación de prueba de SDL. Han sido portados DOSBox, zlib, libpng, libiconv y FreeCiv a Redox. GCC, newlib y binutils están muy cerca de funcionar nativamente pero todavía hay algunos problemas.

Componentes

Concepto de URL. En Redox todo debe ser una URL. Los registros se almacenan en log://, los daemons usan la interfaz bus://, /dev/null aquí es none://.

fired es el sistema de arranque (SysV, systemd o Upstart en Linux), escrito totalmente en Rust. Usa ficheros Toml para la configuración, recurre a la paralelización pero solo tiene como dependencia el kernel Redox y no hace más cosa que el sistema de arranque (esto es un mensaje indirecto contra systemd).

ZFS. El sistema de archivos principal será el magnífico ZFS de Sun/Oracle. Todavía está en desarrollo pero el trabajo se está concentrando exclusivamente en ZFS.

Oxide. Oxide es el gestor de paquetes de Redox. Todavía muy verde.

Lua. Lua es el lenguaje usado para realizar scripts en Redox.

Ion. Un shell más compatible con UNIX que Lua. Inspirado en fish y zsh.

Bohr. El sistema gráfico de Redox.

Orbital. El sistema de ventanas de Redox.

Rust Essentials, reseña del libro

Dicen que a las personas importantes les pide la gente su opinión. Así que no entiendo porque tengo ahora que dar opiniones…

Hoy voy a hablar del libro Rust Essentials de Ivo Balbaert. En primer lugar quiero agradecer a la editorial Packt Publishing por haber contado conmigo a la hora de valorar este libro para que todos vosotros conozcais algo más acerca de él.

RustEssentials

Rust Essentials es un libro de introducción al lenguaje de programación Rust, lenguaje del que ya he hablado anteriormente. El libro está en inglés y asume que no conoces nada o muy poquito de Rust pero sí que has programado con anterioridad. Así pues, el libro no explica conceptos de programación tales como funciones o variables sino que directamente expone sus peculiaridades. Es recomendable haber programado C para entender algunas partes del libro al 100%.

El libro se estructura en 9 capítulos, a saber:

  • Starting with Rust
  • Using variables and types
  • Using functions and control structures
  • Structuring data and matching patterns
  • Generalizing code with high-order functions and parametrization
  • Pointers and memory safety
  • Organizing code and macros
  • Concurrency and parallelism
  • Programming at the boundaries

En estos temas se tratan desde cosas tan triviales como los comentarios (que no lo son, pues según explica el libro, puedes hacer comentarios de RustDoc, que serán compilados como documentación en HTML y tienen marcado Markdown) hasta la gestión multihilo de Rust, para aprovechar uno de los 3 apartados en los que se enfoca Rust: la concurrencia.

Veremos la magia de Rust, respetando la convención de estilo (esto es importante, no vaya a pasar como con JavaScript) y las características que hacen de Rust un gran lenguaje de programación. El libro contiene ejercicios e incluso analizarás porque en determinados lugares obtenemo un error de compilación.

Hacen falta un tiempo para que dejes de ver al compilador de Rust como un protestón sin sentido y lo empieces a ver como tu mejor amigo en la programación

El libro también se adentra a explicar las partes de programación funcional de Rust, no sin antes explicar las closures y las funciones de primer orden. Más tarde nos adentramos en las traits, que posibilitan la programación orientada a objetos pero no como se plantea desde C++, C# o Java. En Rust, es mucho más flexible y unido a las funciones genéricas podemos evitar la repetición del código en un 100%. DRY (don’t repeat yourself). El capítulo 6 es interesante y quizá algo denso para alguien que venga de lenguajes donde la gestión de memoria es administrada por una máquina virtual o intérprete. No es difícil, pero hay que saber las diferencias. Rust tiene muchos tipos de punteros y he de decir que este libro los explica mejor que mi antiguo libro de C de Anaya.

Rust

Más tarde se ve el sistema de módulos y la creación de macros en Rust. Las macros en Rust son muy potentes, más que en C donde también son bastante usadas. El capítulo 8 se dedica por completo a los hilos y la gestión de datos entre distintos hilos. El capítulo 9 nos explica cosas interesantes pero que no tienen mucha densidad y no se merecen un capítulo propio como la intercomunicación entre C y Rust o instrucciones en ensamblador directamente en el código.

Me gusta que tenga ejercicios para practicar (las soluciones están en GitHub), que use las herramientas disponibles de Cargo, que explique porque un determinado código no compilará, que hable de como desarrollar tests unitarios y de que explore todas las características del lenguaje de manera incremental, muchas veces modificando ejemplos anteriores.

No me gusta que quizá sea un libro muy rápido que presupone algunos conceptos y que casi no explora la librería estándar mas que para hablar de ciertas traits muy útiles y la gestión de hilos. No habla en ningún momento de como leer archivos por ejemplo aunque en el anexo menciona librerías para leer distintos tipos de archivos.

En definitiva es un libro que puede estar bien para todos aquellos con experiencia programando y quieran aprender un nuevo lenguaje, lleno de peculiaridades diseñadas para trabajar en: velocidad, seguridad y concurrencia. No se lo recomendaría a alguien que no hubiese programado nunca.

Actualmente existen libros mejores en el mercado y además, en Adrianistán puedes aprender con Rust 101, mi tutorial de Rust.

La gestión de la memoria en Rust

Finalmente ha sido publicada la versión 1.0 de Rust. El lenguaje diseñado por Mozilla basado en 3 principios:

  • Seguridad
  • Concurrencia
  • Rendimiento

Hoy voy a hablar del primer principio, la razón principal para querer ser un sustituto de C++. Porque C++ está bien, pero puedes liarla mucho si no sabes lo que haces.

Rust

El concepto de dueño

En Rust todo tiene un dueño. No puede haber más de uno ni ninguno, debe ser uno exactamente.

Hasta aquí todo es sencillo. Ahora pasaremos la variable A a otra función.

El programa compila y nos da el resultado, que es 9. En los lenguajes de bajo nivel las variables pueden usar memoria del stack o del heap. Un pequeño repaso sobre sus diferencias.

Stack
  • Se reserva su espacio en RAM cuando el programa arranca
  • Son más rápidas de acceder
  • No se les puede cambiar el tamaño
  • Son más seguras
Heap
  • Se debe reservar manualmente la RAM cuando queramos
  • Son más lentas de acceder
  • Pueden cambiar su tamaño en tiempo real
  • Son menos seguras. Pueden dar lugar a fugas de memoria.

En este último caso, la variable A cuyo dueño es main() le pasa la propiedad temporalmente a sumar(). La propiedad se devuelve a main() rápidamente y esta garantizado que así suceda. El compilador lo permite. Veamos ahora un ejemplo más complejo.

Veamos ahora un código más complejo

Por supuesto el código compila pero este de aquí abajo no y solo he cambiado una línea.

La razón es que cuando creamos la estructura de App por primera vez le prestamos config a la estructura app. Así la función main no le puede pasar la propiedad a backup porque ya se la prestó a app.

Préstamos

Para solucionar este problema Rust usa los préstamos. Así la propiedad de config seguirá siendo main() pero lo podrán usar las estructuras app y backup. Para usar referencias usamos el símbolo &.

La estrucura ahora acepta &Config en vez de Config. Es de decir usa una referencia en vez de un valor. Sin embargo esto no compilará. El compilador normalmente deduce si es posible hacer una referencia a algo no existente, un fallo común en C++. En caso de tener dudas no compilará. Rust es bastante inteligente pero no es mágico. En el caso de la estructura App, es necesario indicar que la propiedad config vivirá el mismo tiempo que la estructura.

He usado la anotación de tiempo llamada a. Puedes poner cualquier nombre pero a es muy corto.

Implementaciones y préstamos

Voy a introducir un concepto de Rust que son las implementaciones. Para haceros una idea rápida, serían como clases de C++, pero solo alojan funciones.

He creado dos funciones para implementar App. Son idénticas salvo por un pequeño detalle, una toma el valor self (como this en C++) por referencia y la otra toma el valor directamente.

Compila y funciona. Cambiemos el orden.

Ya no compila. La razón es que cuando llamamos a delete() estamos prestando app entera. Ahora delete() es la dueña de app y cuando salimos de la función eliminamos app porque si su dueña ha muerto, app también debe morir (no es tan sangriento como pensais). Rust lo detecta y delete() será la última función que podemos llamar de app. Por cierto si os preguntais como funcionan las implementaciones en Rust (que no son clases), este código haría lo mismo llamando a funciones estáticas. Quizá así veais mejor como se pasa el concepto de dueños y préstamos.

Diversión con punteros en el heap

Todo estas variables eran del stack que siempre es la manera más sencilla de operar. Vamos ahora a ver como funcionaría esto con punteros. Los punteros operan como variables en el stack que hacen referencia a partes de la memoria que están en el heap. En Rust podemos operar con punteros con máxima seguridad pues todo lo aplicable a variables en el stack sigue siendo válido. Solo hay un dueño y podemos hacer referencias, aunque quizá necesitemos marcar el tiempo de vida manualmente.

Ahora el valor 42 estará en el heap y con puntero podremos acceder a él. Sin embargo como es lógico, no podemos operar directamente con él.

Para operar el valor directamente tenemos que derreferenciarlo. Se usa *

Así que esta operación sería correcto. Nótese el uso de mut para permitir editar el valor. En Rust por defecto las variables no son mutables. Ese privilegio tiene que ser declarado por adelantado.

Como curiosidad mencionar que la macro println! (en Rust si algo termina con ! es una macro) acepta puntero o *puntero indistintamente ya que se da cuenta si es necesario derreferenciar o no.

El problema final

¿Qué pasaría si copiamos un puntero en otro? Pues como un valor en el heap solo puede tener un dueño, la propiedad será del último puntero.

Como curiosidad, este es un curioso método para bloquear en un determinado momento el acceso de escritura a nuestro puntero aunque es fácil volver a obtener el acceso a escritura con un nuevo cambio de dueño.

Conclusiones

Podemos ver que es un lenguaje que presta mucha atención a la seguridad. C++ es mucho más liberal en ese sentido y Mozilla cree que es un problema a la hora de desarrollar grandes aplicaciones. ¿Qué te ha parecido? Si tienes alguna duda no titubees y pregunta.

Crea tu propio lenguaje de programación

Esta entrada la escribí en DesdeLinux hace ya un tiempo y la quiero conservar aquí. La entrada no es la original sino que la he modificado para que siga vigente – MAYO DE 2015

LenguajesProgramacion

Después de escribir el primer artículo sobre cómo crear tu propio sistema operativo, alguien me dijo que si podía hacer un artículo sobre cómo crear un lenguaje de programación. Al principio no hice mucho caso, pero ahora y por otros caminos he aprendido bastante más sobre la creación de los lenguajes de programación. Así pues, vamos a hacer un lenguaje de programación básico, fácilmente empotrable en otros programas y que funcione con una máquina virtual que también diseñaremos. Hoy nos toca hacer la máquina virtual más básica.

Probablemente te preguntes: “¿una máquina virtual? ¿Pero eso no es muy difícil y además ralentiza los programas?” Al contrario, una máquina virtual simple es muy sencilla y relativamente rápida. He elegido Rust como lenguaje para la máquina virtual. Pero, ¿qué es Rust?

Rust es un lenguaje de programación que está enfocado en la seguridad en las ejecuciones, así que utilizándolo será prácticamente imposible que alguien consiga cerrar la máquina virtual. Es un lenguaje compilado en desarrollo creado por Mozilla. Servo, el sustituto de Gecko, se está desarrollando en él. Todavía puede cambiar su sintaxis pero el código que voy a usar va a mantenerse hasta la primera versión estable.

Rust se instala en Linux de manera sencilla. Antes se podía usar un PPA pero ahora el script de RustUp es muy bueno y se encarga de todo.

¿Cómo funciona una máquina virtual?

Si sabes como funciona el mundo en ensamblador es exactamente igual, con el stack o la pila. Si no, te lo explico. Imaginémonos el siguiente código:

El ordenador no entiende lo que significa 2+3, ni tampoco sabe qué orden hay que seguir. Los ordenadores funcionan con pilas o stacks en los que se van acumulando datos y se van sacando continuamente. Ese código en nuestra máquina virtual debería ser algo parecido a esto:

Básicamente, pondríamos el 2 en la pila en lo alto, el 3 también. ADD sacaría (es decir, lo elimina de la pila y obtiene su valor) los 2 últimos elementos de la pila y añadiría el resultado en lo alto de la pila. PRINT cogería el último elemento de la pila y lo usaría para mostrárnoslo. Ahora hagamos eso en Rust.

Ahora es cuando deberías descargarte el código fuente que está en GitHub. Voy a empezar por el archivo vm.rs

Primeramente deberemos definir un lenguaje para el Bytecode, podríamos usar uno ya existente como el de Java o el CLR de .NET/Mono, pero vamos a crear nosotros uno más básico.

 

Usamos notación hexadecimal para cada instrucción. Para hacer la traducción entre el código hexadecimal y la instrucción voy a usar la librería (crate en el argot de Rust) de enum_primitive. Antes se podía usar #[derive(FromPrimitive)] pero en Rust 1.0 no está disponible.

Ahora debemos hacer una función que ejecute cada una de esas instrucciones. Para ello debemos leer un byte y compararlo con las instrucciones que tenemos en la enumeración. Si se encuentra alguna que exista se debe ejecutar su acción.

 

Eso hacemos para leer cada byte individualmente y para ejecutarlas:

 

Como ven, diferenciamos si antes se nos dio la orden de PUSH (nuestra orden INTEGER), el siguiente byte será llevado completamente a la pila. Ahí estamos usando dos funciones que no les he enseñado, self.pop() y self.push(), que se encargan obviamente de manejar el stack.

 

No son muy complejas, pero la función de pop tiene mecanismos de detección de errores. De hecho, en Rust, si quitásemos esos mecanismos nos daría un error de compilación. Ahora simplemente debemos llamar en un programa a Perin (nuestra máquina virtual) y que ejecute un bytecode.

 

Ese bytecode puede ser leído de un fichero, pero aquí para simplificar lo he almacenado en una variable. Si lo ejecutamos nos dará el resultado esperado:

Todo el código está disponible en GitHub bajo la Apache License 2.0: https://github.com/AdrianArroyoCalle/perin. Para compilar deben tener Cargo instalado y poner: