Portando el Big Bang de Space Settler a Rust

Hace ya un tiempo que no se habla en este blog de lo que hago en mi tiempo libre. Probablemente porque hace ya un tiempo que no tengo tiempo libre como para tener vida y dedicarla a algo que me guste realmente. No obstante, hace poco he decidido que prefiero dejar algo más de lado los estudios y dedicarme al desarrollo puro, como a mi me gusta. Esto puede que provoque una cierta bajada de rendimiento en mis estudios, pero opino que me va a suponer una mejora sustancial de la calidad de vida.

En esta cruzada contra la explotación universitaria, a parte de haber realizado grandes críticas y reuniones con la gente que puede intentar reducir la excesiva carga de trabajo, he decidido comenzar a aprender un nuevo lenguaje: Rust. Y como considero que la mejor manera de aprender un nuevo lenguaje es creando un proyecto con el, he comenzado a portar el Big Bang de Space Settler a este lenguaje.

RustNo es un proceso fácil. Rust es un lenguaje muy cercano a la máquina, y muy nuevo, con una orientación muy definida hacia la concurrencia, la eficiencia y con toques de C, C++ y lenguajes funcionales. Además, trae un concepto muy, muy novedoso que al principio puede costar entender: la posesión de memoria. En Rust no hay variables (explicitamente), hay lo que el lenguaje llama «bindings» que no son más que nombres que se apropian de memoria. Se pueden usar como variables fuertemente tipadas, pero el concepto es totalmente distinto.

En Rust, un binding posee cierta memoria, y se puede prestar a una referencia. No obstante, mientras esta referencia tenga el control de la memoria solo ella puede modificarla. Esto permite evitar los data-races y la inexistencia de punteros nulos evita las violaciones de segmentos. Este control se hace en compilación con un montón de sistemas que están bastante bien explicados en el libro oficial, y no tienen lugar en este artículo.

En cuanto a Space Settler, en su día ya existía un sistema para crear un universo relativamente realista basado en estadísticas reales. Este universo (con algunos fallos) se creaba mediante un algoritmo bastante complejo, escrito en PHP y cuya ejecución tardaba mucho, mucho tiempo. Dado que rust es un lenguaje compilado, casi equivalente a C y potencialmente más eficiente que C++ (sobretodo por evitar memory leaks), el Big Bang en Rust ha de ser mucho más eficiente y rápido.

El código está disponible en GitHub, y voy a explicar algunas cosas curiosas que me he encontrado. Por ejemplo, una simple multiplicación puede no ser tan fácil de resolver en Rust, entre otras cosas porque es un lenguaje muy explícito. Aquí tenemos un código para calcular un volumen de una esfera en PHP:

public function volume()
{
    return 4/3*M_PI*pow($this->radius(), 3);
}

Este mismo código, en Rust es algo más complejo:

fn get_volume(&self) -> f64 {
    4_f64/3_f64*PI*self.radius.powi(3)
}

Veamos los cambios. Dejando de lado que he cambiado el nombre de la función, y los pequeños cambios sintácticos de fn como declaración en lugar de function y que en Rust he decidido hacerla privada, vemos que el tipo de retorno (float de 64 bits) se coloca tras la declaración de la función y que el objeto en cuestión aquí se incluye como atributo (&self) que además es una referencia. Pero lo que más me ha llamado la atención ha sido que el 4/3 lo he tenido que declarar como 4_f64/3_f64. Esto es porque en Rust solo se pueden hacer operaciones como esta se requiere que sean del mismo tipo, por lo que hay que aclararle al compilador que tanto el 4 como el 3 serán floats de 64 bits.

Otro cambio interesante es la potencia. Es una función que está declarada como implementación de f64. Y es más, dado que estoy calculando una potencia entera (el cubo) he de usar powi() en lugar de powf(). En cambio, en el caso de los enteros solo existe una función: pow(). Bajo mi punto de vista esto es un error, ya que el compilador debería ser lo suficientemente inteligente como para saber que 3 es un entero y usar la implementación de potencias a enteros.

Como último detalle, el hecho de que no hay punto y coma al final de la expresión. Esto sucede por dos cosas: primero, la última expresión de algo que está entre corchetes en Rust es el retorno automático. Puedes hacer un return, pero no es necesario, a no ser que sea un return con código opcional después. Además, en Rust, todo es una expresión y se puede asignar. Se puede asignar el resultado de un if, de un match (una especie de switch) o de lo que sea. Y esto no requiere punto y coma, ya que es solo parte de la expresión (el punto y coma irá al final de cada expresión).

Rust supone un cambio de paradigma interesante en la programación. El concepto de posesión de memoria me ha gustado mucho. La mutabilidad de las variables también (se puede definir que una variable o referencia no sea mutable/cambiable en un contexto concreto). Además, he podido comprobar que el compilador de Rust explica muy bien los problemas y hasta da soluciones.

Galaxia Messier 74

Galaxia Messier 74 por el telescopio Hubble

De momento he implementado la creación de estrellas, y estas se crean en apenas décimas de segundo (mucho más rápido que en PHP, aunque queda por hacer estadísticas). El siguiente paso es implementar los planetas y dar con una manera de guardar todos estos datos. Se está pensando en noSQL por su facilidad de extracción de información jerárquica, y especialmente en HyperDex, ya que a parte de ser una tecnología nueva y atractiva, su función de búsqueda rapidísima llama mucho la atención. Se está planteando (somos varios compañeros) en desarrollar finalmente Space Settler, aunque no va a ser no pensado inicialmente.

Pronto tendréis más noticias del tema, pero de momento, he de confesar que estoy muy a gusto con este nuevo lenguaje y con este proyecto.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.