Novedades de C++17

Después de tres años de trabajo, C++17 ha sido finalmente estandarizado. Esta nueva versión de C++ incorpora y elimina elementos del lenguaje, con el fin de ponerlo al día y convertirlo en un lenguaje moderno y eficaz. El comité ISO de C++ se ha tomado muy en serio su labor, C++11 supuso este cambio de mentalidad, que se ha mantenido en C++14 y ahora en C++17, la última versión de C++.

Repasemos las noveades que incorpora C++17 respecto a C++14

if-init

Ahora podemos incluir una sentencia de inicialización antes de la condición en sentencias if y switch. Esto es particularmente útil si queremos operar con un objeto y desconocemos su validez.

// ANTES
Device dev = get_device();
if(dev.isOk()){
    dev.hacerCosas();
}

// AHORA
if(Device dev = get_device(); dev.isOk()){
    dev.hacerCosas();
}

Declaraciones de descomposición

Azúcar sintántico que permite mejorar la legibiliad en ciertas situaciones. Por ejemplo, en el caso de las tuplas, su uso se vuelve trivial.

// FUNCIÓN QUE DEVUELVE TUPLA
std::tuple<int, std::string> funcion();

// C++14
auto tup = funcion();
int i = std::get<0>(tup);
std::string s = std::get<1>(tup);

// C++17
auto [i,s] = funcion();

Esto funciona para multitud de estructuras de datos, como estructuras, arrays, std::array, std::map,…

std::map m = ...;
for(auto && [key, value] : m){

}

Deduction Guides

Ahora es menos necesario que nunca indicar los tipos en ciertas expresiones. Por ejemplo, al crear pares y tuplas:

// ANTES
auto p = std::pair<int,std::string>(42,"Adrianistan");

// AHORA
auto p = std::pair(42,"Adrianistan");

Esto por supuesto también sirve para estructuras y otras construcciones:

template<typename T>
struct Thingy
{
  T t;
};

// Observa
Thingy(const char *) -> Thingy<std::string>;

Thingy thing{"A String"}; // thing.t es de tipo std::string

template auto

// ANTES
template <typename T, T v>
struct integral_constant
{
   static constexpr T value = v;
};
integral_constant<int, 2048>::value
integral_constant<char, 'a'>::value

// AHORA
template <auto v>
struct integral_constant
{
   static constexpr auto value = v;
};
integral_constant<2048>::value
integral_constant<'a'>::value

Fold expressions

Imagina que quieres hacer una función suma, que admita un número ilimitado de parámetros. En C++17 no se necesita apenas código.

template <typename... Args>
auto sum(Args&&... args) {
   return (args + ... + 0);
}

Namespaces anidados

Bastante autoexplicativo

// ANTES

namespace A{
    namespace B {
        bool check();
    }
}

// AHORA

namespace A::B {
    bool check();
}

Algunos [[atributos]] nuevos

[[maybe_unused]]

Se usa para suprimir la advertencia del compilador de que no estamos usando una determinada variable.

int x = 5;
[[maybe_unused]] bool azar = true;
x = x + 10

[[fallthrough]]

Permite usar los switch en cascada sin advertencias del compilador.

switch (device.status())
{
case sleep:
   device.wake();
   [[fallthrough]];
case ready:
   device.run();
   break;
case bad:
   handle_error();
   break;
}

Variables inline

Ahora es posible definir variables en múltiples sitios con el mismo nombre y que compartan una misma instancia. Es recomendable definirlas en un fichero de cabecera para luego reutilizarlas en ficheros fuente.

// ANTES
// en una cabecera para que la usasen los demás
extern int x;

// solo en un fichero fuente, para inicializarla
int x = 42;
// AHORA

// en la cabecera
inline int x = 42;

if constexpr

Ahora es posible introducir condicionales en tiempo de compilación (similar a las macros #IFDEF pero mejor hecho). Estas expresiones con constexpr, lo que quiere decir que son código C++ que se evalúa en tiempo de compilación, no de ejecución.

template<class T>
void f (T x)
{
    if  constexpr(std:: is_integral <T>::value)  {
        implA(x);
    }
    else  if  constexpr(std:: floating_point <T>::value)  {
        implB(x);
    }
    else
    {
        implC(x);
    }
}

std::optional

Tomado de la programación funcional, se incorpora el tipo optional, que representa un valor que puede existir o no. Este tipo ya existe en Rust bajo el nombre de Option y en Haskell como Maybe.

std::optional opt = f();
if(opt)
    g(*opt);

// otra opción de uso si queremos proveer de un reemplazo
std::optional opt = f();
std::cout << opt.value_or(0) << std::endl;

std::variant

Descritas como las unions pero bien hechas. Pueden contener variables de los tipos que nosotros indiquemos.

std::variant<int, double, std::vector> precio; // precio puede ser un int, un double o un std::vector

// comprobar si el valor en un variant es de un determinado tipo
if(std::holds_alternative<double>(precio))
    double x = std::get<double>(precio);

std::any

Si con std::variant restringimos los posibles tipos de la variable a los indicados, con std::any admitimos cualquier cosa.

std::any v = ...;
if (v.type() == typeid(int)) {
   int i = any_cast<int>(v);
}

std::filesystem

Se añade a la librería estándar este namespace con el tipo path y métodos para iterar y operar con directorios. Dile adiós a las funciones POSIX o Win32 equivalentes.

#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;

void main(){
  fs::path dir = "/";
  dir /= "sandbox";
  fs::path p = dir / "foobar.txt";
  std::cout << p.filename() << "\n";
  fs::copy(dir, "/copy", fs::copy_options::recursive);
}

Algoritmos en paralelo

Muchos de los algoritmos de STL ahora pueden ejecutarse en paralelo bajo demanda. Con std::execution::par indicamos que queremos que el algoritmo se ejecute en paralelo.

std::sort(std::execution::par, first, last);

¿Qué novedades se esperan en C++20?

Ya hemos visto lo que trae C++17. Ahora veremos que se espera que traiga C++20 en 2020.

  • Módulos. Reemplazar el sistema de includes
  • Corrutinas. Mejorar la programación asíncrona
  • Contratos. Mejorar la calidad del código
  • Conceptos. Mejorar la programación genérica
  • Redes. Estandarizar la parte de red en C++ tal y como se ha hecho con std::filesystem
  • Rangos. Nuevos contenedores

Referencias:

 

loading...

Tutorial de Rocket, echa a volar tus webapps con Rust

Previamente ya hemos hablado de Iron como un web framework para Rust. Sin embargo desde que escribí ese post ha surgido otra librería que ha ganado mucha popularidad en poco tiempo. Se trata de Rocket. Un web framework que propone usar el rendimiento que ofrece Rust sin sacrificar la facilidad de uso de otros lenguajes.

Rocket lleva las pilas cargadas

A diferencia de Iron, Rocket incluye bastantes prestaciones por defecto con soporte para:

  • Plantillas
  • Cookies
  • Formularios
  • JSON
  • Soporte para rutas dinámicas

Un “Hola Mundo”

Rocket necesita una versión nightly del compilador de Rust. Una vez lo tengas creamos una aplicación con Cargo.

cargo new --bin rocket_app

Ahora modificamos el fichero Cargo.toml generado en la carpeta rocket_app para añadir las siguientes dependencias:

rocket = "0.2.4"
rocket_codegen = "0.2.4"
rocket_contrib = "*"

Editamos el archivo src/main.rs para que se parezca algo a esto:

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "El cohete ha despegado"
}

fn main() {
    rocket::ignite().mount("/",routes![index]).launch();
}

Con esto iniciamos Rocket y dejamos a la función index que gestione las peticiones GET encaminadas a /. El servidor devolverá El cohete ha despegado.

Ahora si ejecutamos cargo run veremos algo similar a esto:

Vemos que el servidor ya está escuchando en el puerto 8000 y está usando todos los cores (en mi caso 4) del ordenador.

Configurar Rocket

Rocket dispone de varias configuraciones predeterminadas que afectan a su funcionamiento. Para alternar entre las configuraciones debemos usar variables de entorno y para modificar las configuraciones en sí debemos usar un fichero llamado Rocket.toml.

Las configuraciones por defecto son: dev (development), stage (staging) y prod (production). Si no indicamos nada, Rocket se inicia con la configuración dev. Para arrancar con la configuración de producción modificamos el valor de ROCKET_ENV.

ROCKET_ENV=prod cargo run --release

Sería el comando para arrancar Rocket en modo producción. En el archivo Rocket.toml se puede modificar cada configuración, estableciendo el puerto, el número de workers y parámetros extra pero no vamos a entrar en ello.

Rutas dinámicas

Rocket soporta rutas dinámicas. Por ejemplo, si hacemos GET  /pelicula/Intocable podemos definir que la parte del nombre de la película sea un parámetro. Esto hará que la función encargada de /pelicula/Intocable y de /pelicula/Ratatouille sea la misma.

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/pelicula/<pelicula>")]
fn pelicula(pelicula: &str) -> String {
    format!("Veo que te gusta {}, a mi también!",pelicula)
}

#[get("/")]
fn index() -> &'static str {
    "El cohete ha despegado"
}

fn main() {
    rocket::ignite().mount("/",routes![index,pelicula]).launch();
}

Los argumentos de la función son los parámetros de la petición GET. ¿Qué pasa si no concuerda el tipo de la función con lo que se pasa por HTTP? Nada. Sencillamente Rocket ignora esa petición, busca otra ruta (puede haber sobrecarga de rutas) y si encuentra otra que si satisfaga los parámetros será esa la escogida. Para especificar el orden en el que se hace la sobrecarga de rutas puede usarse rank. En caso de no encontrarse nada, se devuelve un error 404.

POST, subir JSON y formularios

Rocket se integra con Serde para lograr una serialización/deserialización con JSON inocua. Si añadimos las dependencias serde, serde_json y serde_derive al fichero Cargo.toml podemos tener un método que acepete una petición POST solo para mensajes del tipo application/json con deserialización incorporada.

#![feature(plugin)]
#![plugin(rocket_codegen)]

#[macro_use] extern crate rocket_contrib;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate rocket;

use rocket_contrib::{JSON, Value};

#[derive(Serialize,Deserialize)]
struct User{
    name: String,
    email: String
}

#[post("/upload", format="application/json", data="<user>")]
fn upload_user(user: JSON<User>) -> JSON<Value> {
    JSON(json!({
        "status" : 200,
        "message" : format!("Usuario {} registrado con éxito",user.email)
    }))
}

fn main() {
    rocket::ignite().mount("/",routes![upload_user]).launch();
}

Si el JSON no se ajusta a la estructura User simplemente se descarta devolviendo un error 400.

Lo mismo que es posible hacer con JSON puede hacerse con formularios usando el trait FromForm.


#![feature(plugin,custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use] extern crate rocket_contrib;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
extern crate rocket;

use rocket_contrib::{JSON, Value};
use rocket::request::{FromForm, Form};

#[derive(FromForm)]
struct User{
    name: String,
    email: String
}

#[post("/upload", data="<user>")]
fn upload_user(user: Form<User>) -> String {
    format!("Hola {}",user.get().name)
}

fn main() {
    rocket::ignite().mount("/",routes![upload_user]).launch();
}

Errores

En Rocket, como es lógico, es posible crear páginas personalizadas para cada error.

#![feature(plugin,custom_derive)]
#![plugin(rocket_codegen)]

#[get("/")]
fn index() -> &'static str {
    "El cohete ha despegado"
}

#[error(404)]
fn not_found() -> &'static str {
    "La página no ha podido ser encontrada"
}

fn main() {
    rocket::ignite().mount("/",routes![index]).catch(errors![not_found]).launch();
}

La lista de métodos que manejan errores hay que pasarla en el método catch de rocket::ignite

Respuestas

Rocket nos permite devolver cualquier cosa que implemente el trait Responder. Algunos tipos ya lo llevan como String, File, JSON, Option y Result. Pero nada nos impide que nuestros propios tipos implementen Responder. Con Responder tenemos el contenido y el código de error (que en la mayoría de casos será 200). En el caso de Result es muy interesante, pues si Err contiene algo que implementa Responder, se devolverá la salida que implemente también, pudiendo así hacer mejores respuestas de error, mientras que si no lo hacen se llamará al método que implemente el error 500 de forma genérica. Con Option, si el valor es Some se devolverá el contenido, si es None se generará un error 404.

#![feature(plugin,custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use] extern crate rocket_contrib;
extern crate rocket;

use rocket::response::{self, Responder, Response};
use std::io::Cursor;
use rocket::http::ContentType;

struct Pelicula{
    nombre: &'static str,
    pais: &'static str
}

impl<'r> Responder<'r> for Pelicula{
    fn respond(self) -> response::Result<'r> {
        Response::build()
        .sized_body(Cursor::new(format!("La película {} se hizo en {}",self.nombre,self.pais)))
        .header(ContentType::new("text","plain"))
        .ok()
    }
}

#[get("/pelicula/<pelicula>")]
fn pelicula(pelicula: &str) -> Result<Pelicula,String> {
    let intocable = Pelicula{
        nombre: "Intocable",
        pais: "Francia"
    };
    let madMax = Pelicula{
        nombre: "Mad Max",
        pais: "Estados Unidos"
    };
    match pelicula {
        "Intocable" => Ok(intocable),
        "Mad Max" => Ok(madMax),
        _ => Err(format!("No existe esa película en nuestra base de datos"))
    }
}

#[get("/")]
fn index() -> Result<String,String> {
    Err(format!("No implementado"))
}

#[error(404)]
fn not_found() -> &'static str {
    "La página no ha podido ser encontrada"
}

fn main() {
    rocket::ignite().mount("/",routes![index,pelicula]).catch(errors![not_found]).launch();
}

Este ejemplo para /pelicula/Intocable devolverá: La película Intocable se hizo en Francia mientras que para /pelicula/Ratatouille dirá No existe esa película en nuestra base de datos.

También es posible devolver plantillas. Rocket se integra por defecto con Handlebars y Tera, aunque no es muy costoso añadir cualquier otra como Maud.

Conclusión

Rocket es un prometedor web framework para Rust, bastante idiomático, que se integra muy bien con el lenguaje. Espero con ansia las nuevas veriones. Es posible que la API cambie bastante hasta que salga la versión 1.0, no obstante así es como ahora mismo funciona.

Rust en 5 minutos – #PicnicCode2017

El pasado 17 de marzo fue el Picnic Code en la Universidad de Valladolid. En el evento, organizado por el GUI y Cylicon Valley, tuve el honor de dar una Lightning Talk. Se trata de una charla de 5 minutos muy rápidos para exponer una idea. Mi Lightning Talk titulada Rust en 5 minutos iba dirigida a enseñar, sin entrar en muchos detalles, aquellas características que hacen de Rust un lenguaje seguro. No estaba nervioso hasta que subí al escenario… ¡y entonces ya empecé a estarlo! Hay algunos fallos frutos de los nervios y las diapositivas… bueno, podían haber funcionado mejor.

En cualquier caso, estáis invitados a ver Rust en 5 minutos.

The Pitts Circus, la primera película financiada con Ethereum

Todos los días me sorprendo de las cosas que son capaces de hacer la gente con Ethereum. Uno de las primeras apliaciones que surgieron fue el crowdfunding distribuido. ¿Te imaginas un Kickstarter P2P? Pues con Ethereum es posible implementarlo.

Siguiendo estas ideas surge The Pitts Circus, la primera película financiada con Ethereum.

La película

Se trata de una cienta de terror-comedia que incorpora las habilidades, talento cómico y naturaleza única de una familia de circo real de Australia. La familia circense Pitts ha estado de gira por los cinco continentes con su espectáculo. Cecil Pitt también es un músico consumado, forma parte de la banda musical Barkers Vale Brothers. Él se hará cargo de la banda sonora de la película ya que participó en todos los episodios de Karnydale (otro proyecto de los productores de la cinta) La familia contará con: los dos padres, un chico de 11 años, una niña de 6 años y un niño de 1 año. Disfruta de este cuento de hadas circense, ambientado en el remoto oeste de Australia y Suiza, con acróbatas, payasos, un sacerdote, niños diabólicos y caníbales.

¿Cómo funciona?

Inicialmente se han creado 666 acciones del proyecto, estas se compran vía Ethereum y el smart contract asociado se encargará de repartirnos los beneficios que genere la película (si los hubiera) durante 20 años. Para evitar situaciones similares a lo ocurrido con la DAO, el crowdfunding no se basa exclusivamente en Ethereum sino que hay un respaldo legal en Suiza. La compañía productora es aKenEvilThing, una empresa fundada en 2014 en Suiza con varios proyectos anteriores.

Si quiéres colaborar con la financiación del proyecto lo único que tienes que hacer es enviar una cantidad determinada de Ether según el número de acciones que quieras comprar (1 acción = 10 ETH) a la dirección que aparece en su página web.

Ahora mismo el equipo está de rodaje y se espera que para finales de 2017 ya pueda presentarse a algunos festivales de cine. Algunos actores confirmados aparte de la familia Pitts son: Carlos Henriquez y Matto Kämpf.

 

Entrevista con Tony Caradonna

Pregunta: Tony, ¿puedes contarnos un poco acerca de la película?
Tony Caradonna: “The Pitts Circus es una película de horror-comedia ficticia protagonizada por los “Pitts”; una familia real de un circo a las afueras de Australia, justo donde las primeras escenas están siendo filmadas antes de viajar a Suiza para terminar el rodaje. En 2018 la película independiente se presentará en festivales de cine antes de su lanzamiento en cines selectos en todo el mundo y por Video-on-Demand. Lo que realmente nos emociona es que la película es la primera del mundo que se financia completamente con Ethereum “.
Pregunta: Como realizaron esto? Y por qué decidieron financiar el film con Ethereum?
Tony Caradonna: “La película es financiada por 666 acciones de crowdfunded, con un costo por acción de diez Ethereum (que son aproximadamente 97 dólares americanos para el momento en que se escribió esta nota). Los accionistas recibirán el 50% de los ingresos de la película por un período de 20 años garantizados por contratos inteligentes: contratos auto ejecutables basados en leyes suizas que utilizan protocolos informáticos basados en la cadena de bloques de Ethereum para verificar y hacer cumplir las cláusulas acordadas por sus firmantes. Esto se traduce en un acuerdo de contrato más rápido y seguro para todos. El Pitts Circus es uno de los primeros proyectos rentables en el mundo real que está conectado a la cadena de bloques, por lo que a mi parecer hace que sea una gran manera de mostrar a la gente común la propuesta de valor en blockchain y moneda digital”.
Pregunta: ¿Qué más podemos esperar de esta película y la compañía productora?
Tony Caradonna: “Queremos ver más participación de la comunidad en la producción de películas, desde el casting hasta el argumento. Hemos desarrollado nuestro propio activo accionario para ayudar a conseguir lo que llamamos EMV-coin (Ethereum Movie Coin). Nuestras monedas EMV se distribuirán gratuitamente a todos nuestros accionistas, con una ICO planeada para adquirir monedas adicionales en el futuro y que podría aumentar la participación de los consumidores en futuras producciones. Las monedas permitirán a los consumidores agregar o votar por propuestas, nuevos contenidos y la dirección estratégica de futuras producciones. Estamos creando un caso real de negocios a escala mundial que muestra lo que es posible hacer con la plataforma de Ethereum “.
Pregunta: ¿Entonces la moneda EMV es un activo que nos da la posibilidad de decidir sobre futuras películas permitiéndonos votar para evitar historias exageradas y finales que dan paso a nuevas experiencias en pantalla? ¿Las monedas EMV también benefician el ROI de la película?
Tony Caradonna: “Sí, exactamente. Este enfoque de toma de decisiones de producción significa que los consumidores ven lo que quieren ver. Los contribuyentes pueden intercambiar nuevas ideas con la posibilidad de que la comunidad vote para que se produzca alguna de ellas. Esto equivale a menores costos de producción para la película que sugiera la comunidad, y mayores ventas, ya que las ideas han sido previamente validadas por el consumidor. La combinación de presupuestos de producción más bajos con mayores ingresos recompensa a los inversionistas con mejores beneficios. Los poseedores de monedas EMV se benefician del contenido que ellos mismos ayudan a generar”.
Pregunta: ¿Qué puedes ver para la industria cinematográfica en el futuro después del lanzamiento de The Pitts Circus?
Tony Caradonna: “Puedo prever que muchas películas se producirán con un modelo similar al nuestro a través de la contribución de la comunidad. Los presupuestos de producción más bajos que estas películas exigen llevarán a que muchas nuevas ideas puedan llegar a la pantalla grande, y que cualquiera pueda aparecer en los créditos de una película. Si Ethereum continúa en su actual avance, espero que el modelo de producción en comunidad de EMV se vuelva muy popular, con muchas personas deseando comprar monedas EMV en los intercambios para también poder participar en el modelo que hemos creado. Esto resultaría muy favorable para el precio en que se cotice en el mercado el EMV “.
Pregunta: ¿Otros planes para el futuro?
Tony Caradonna: “Hemos realizado varias alianzas de negocio con compañías relacionadas al área de las criptodivisas que ayudarán a apoyar la red de monedas EMV incluyendo: Ledger Wallet, Trezor y Ether Card para que el intercambio de monedas de EMV y Ether sea seguro y simple, COVAL para cifrar Bitcoin y Ether en archivos de audio con su plataforma ‘Vocal’. Estas alianzas permitirán la colocación de productos digitales en el film”.

Sobre Tony:

Tony Caradonna tiene un Master en Física y Filosofía. Financió sus estudios haciendo espectáculos como comediante y artista de circo. Estuvo de gira con varios circos en todo el mundo. Allí conoció a Ken Fanning, un director y artista de circo. También conoció a la Familia Pitts, una Familia Australiana de Circo. Su primer encuentro fue en una gira con otro circo australiano 2000/2001. Han trabajado juntos regularmente en varias ocasiones desde entonces. Actualmente, el financiamiento del Swiss National Language Cooperation Arts funding ya está concedido y aún está pendiente un Financiamiento del Swiss National Film Arts

¿Está usted de broma Sr. Feynman?

Acabo de leer un libro, un señor libro, uno de los que más me han gustado recientemente. Y ha sido un placer leerlo.

Se trata de ¿Está usted de broma Sr. Feynman? y es una especie de autobiografía de la vida del físico Richard Feynman. El libro se estructura en anécdotas que va contando que si bien suelen tener un elemento de inicio cronologicamente ordenado con el resto, cada anécdota puede estructurarse de forma diferente.

El libro es muy divertido y derrocha originalidad. Es un claro ejemplo de por qué prefiero los libros de no ficción, ya que superan a la ficción y por mucho.

La vida de Richard Feynman, uno de los grandes físicos del siglo XX, es una completa inspiración. Una invitación a ser curioso, a no tener miedo al qué dirán, a dejar de preocuparse y a disfrutar de las cosas de la vida.

Algunas anécdotas interesantes:

  • La apertura de cajas fuertes en Los Alamos
  • Cabrear a la censura de Los Alamos
  • Introducirse en el mundo de la pintura y llegar a realizar un cuadro para un burdel
  • Tocar la frigideira en una banda de Río de Janeiro
  • Recibir un premio Nobel
  • Dar un seminario de biología en Harvard (acabando justo él de terminar física)
  • Hablar en un idioma inventado en una actuación de scouts
  • Ligar en un local de carretera
  • Y muchas más

Mi más sincera recomendación. Yo ahora empiezo con la segunda parte ¿Qué te importa lo que piensen los demás?