Anuncio de Dart 2.7: Un Dart más seguro y expresivo.

Eduardo CQ
Comunidad Flutter
Published in
9 min readDec 16, 2019

Hola a todos, esta es una traducción al español del artículo “Announcing Dart 2.7: A safer, more expressive Dart” del autor Michael Thomsen.

Hemos anunciado la versión estable del SDK de Dart 2.7, con nuevas capacidades adicionales para desarrolladores. Ha sido un año ocupado para Dart, nuestro lenguaje optimizado para el cliente para aplicaciones rápidas en cualquier plataforma. Hemos enviado seis nuevas versiónes con docenas de nuevas características. Ha sido gratificante ver a la comunidad Dart usar estas características, y estábamos encantados con el reciente informe GitHub Octoverse que incluia a Dart como el idioma #1 de más rápido crecimiento, clasificado por el número de contribuyentes.

Dart 2.7 agrega soporte para métodos de extensión, mas un nuevo paquete para el manejo de strings con carácteres especiales. Tenemos una actualización sobre seguridad nula(tipos anulables y no anulables de tipo seguro) y una nueva experiencia de playground de seguridad nula en DartPad. A nivel de ecosistema, pub.dev tiene una nueva función “Me gusta” para enviar comentarios a los paquetes que aprecia. Dart 2.7 está accesible como una descarga de SDK en dart.dev, y también está integrado en la versión de Flutter 1.12.

Métodos de extensión

Dart 2.7 agrega una nueva y poderosa función de lenguaje largamente solicitada: métodos de extensión. Estos te permiten agregar nueva funcionalidad a cualquier tipo, incluso los tipos de eventos que no controla, y tienen la brevedad y la experiencia de autocompletar de las llamadas a métodos regulares.

Miremos un pequeño ejemplo: agregar soporte para analizar ints y doubles desde Strings. Como desarrolladores de aplicaciónes no podemos cambiar la clase String , porque está definido en la biblioteca dart:core, pero con los métodos de extensión podemos extenderlos! Una vez que defines esta extensión, puedes llamar a un nuevo método parseInt en un String como si el método estuviera definido en la clase String:

extension ParseNumbers on String {
int parseInt() {
return int.parse(this);
} double parseDouble() {
return double.parse(this);
}
}main() {
int i = '42'.parseInt();
print(i);
}

Los métodos de extensión son estáticos

Los métodos de extensión se resuelven y se envían estáticamente, lo que significa que no puedes llamarlos en valores cuyo tipo es dynamic. Aquí la llamada lanza una excepción en tiempo de ejecución:

dynamic d = '2';d.parseInt();→ Runtime exception: NoSuchMethodError

Los métodos de extensión funcionan bien con los tipos de inferencia de Dart, entonces en la siguiente variable se infiere que v tiene un tipo String, y la extensión en String está disponible:

var v = '1';
v.parseInt(); // Works!

Debido a que los métodos de extensión se resuelven estáticamente, son tan rápidos como llamar a una funcion estática o método auxiliar, pero con una sintaxis de invocación mucho más amigable.

Extensiones pueden tener variables de tipo

Imagine que quieres definir una extensión en List para obtener los elementos en índices pares. Te gustaría que esta extensión funcionara en listas de cualquier tipo como la lista de entrada. Puedes hacer esto, haciendo la extensión genérica y aplicando su parámetro de tipo tanto al tipo que extiende como al método de extensión:

extension FancyList() on List<T> {
List<T> get evenElements {
return <T>[for (int i = 0; i < this.length; i += 2) this[i]];
}
}

Los métodos de extensión son realmente miembros de extensión

Llamamos la característica “métodos de extención” porque es una terminología familiar, si has usado la función de lenguaje correspondiente en otros lenguajes de programación. Pero en Dart la función es más general: también soporta clases extendidas con nuevos getters , setters y operadores. En el ejemplo anterior FancyList, evenElements es un getter. Aquí hay un ejemplo de agregar un operador para cambiar strings:

extension ShiftString on String {
String operator <<(int shift) {
return this.substring(shift, this.length) + this.substring(0, shift);
}
}

Grandes ejemplos de la comunidad

Ya has visto muchos desarrolladores en la comunidad de Dart experimentando con métodos de extención. Aquí están algunos usos geniales que hemos visto hasta ahora.

Jeremiah Ogbomo ha creado el time_package, que usa extensiones en num (la clase base para ints y doubles) para habilitar la fácil construcción de objetos Duration:

// Create a Duration via a `minutes` extension on num.
Duration tenMinutes = 10.minutes;
// Create a Duration via an `hours` extension on num.
Duration oneHourThirtyMinutes = 1.5.hours;
// Create a DateTime using a `+` operator extension on DateTime.
final DateTime afterTenMinutes = DateTime.now() + 10.minutes;

Marcelo Glasberg ha creado un paquete i18n(internacionalización) que usa métodos de extensión para simplificar localización de strings:

Text('Hello'.i18n) // Displays Hello in English, Hola in Spanish, etc.

Simon Leier ha creado el paquete dartx, que contiene extensiones para un montón de tipos principales de Dart. Algunos ejemplos:

var allButFirstAndLast = list.slice(1, -2);    // [1, 2, 3, 4]
var notBlank = ' .'.isBlank; // false
var file = File('some/path/testFile.dart');
print(file.name); // testFile.dart
print(file.nameWithoutExtension); // testFile

Brian Egan está actualizando el popular paquete RxDart con métodos de extension para redefinir la API para que funciones con streams.

Manejo seguro de subcadenas

La clase String estandar de Dart usa la codificación UTF-16. Es una elección común en lenguajes de programación, especialmente aquellas que ofrecen soporte para ejecutar ambas nativamente en dispositivos, y en la web.

Strings UTF-16 generalmente funcionan bien, y la codificación es transparente al desarrollador. Sin embargo, cuando se manipulan strings, y especialmente cuando se manipulan strings ingresadas por usuarios, puedes experimentar una diferencia entre lo que el usuario persive como un carácter, y lo que está codificado como una unidad de código en UTF-16. Mira un pequeño ejemplo, extrayendo los primeros tres carácteres de un string ingresado por un usuario:

var input = ['Resume'];
input.forEach((s) => print(s.substring(0, 3)));
$ dart main.dart
Res

No hay problema hasta ahora; se ha imprimido los primeros tres carácteres del string en su lista de entrada, y el resultado es Res. Ahora consideremos usuarios de diferentes regiones, quienes podrían ingresar strings que contengan acentos, Hangul(escritura coreana), e incluso una combinación de emojis para representar el concepto “Currículo”:

// New longer input list:
var input = ['Resume', 'Résumé', '이력서', '💼📃', 'Currículo'];
$ dart main.dart
Res
Ré
이력서
💼�
Cur

Hmm, algunas de esas funcionaron, pero ¿qué pasó con los elementos Résumé y 💼📃? Para Résumé, ¿por qué se obtuvieron dos carácteres string? El problema aquí radica en los rincones oscuros de Unicode. El acento é en Résumé es realidad dos puntos de código, una e y un combinado acento agudo. Y 📃, el emoji página con rizo, es un único punto de código que está codificado con un par sustituto de U+d83d U+dcc3. ¿Confuso?

Como dijimos, a menudo no necesitas preocuparte por los caracteres y los puntos de código. Si todo lo que hace es recibir, pasar y entregar strings enteros, la codificación interna es transparente. Pero si necesitas iterar sobre los caracteres de un string o manipular el contenido de un string, puede meterse en problemas. La buena noticia es que Dart 2.7 presenta un nuevo paquete characters , para manejar estos casos. Este paquete admite strings vistos como secuencias de strings percibidos por el usuario, también conocidos como clústeres de grafemas Unicode . Con el paquete characters podemos arreglar nuestro código con un pequeño cambio en el código que acorta el texto:

// Before:
input.forEach((s) => print(s.substring(0, 3)));
// After, using the characters package:
input.forEach((s) => print(s.characters.take(3)));

Primero creamos un nueva instancia Characters del string en s(usando el .charactersmétodo de extensión conveniente ). Luego usamos el take()método ingenioso para extraer los 3 caracteres iniciales.

Una vista previa técnica de este nuevo paquete está disponible en pub.dev . Nos encantaría conocer tu opinión sobre este paquete. Si encuentra algún problema, por favor repórtelo .

Vista previa de seguridad nula

Hace unos meses, anunciamos nuestra intención de apoyar la seguridad nula en Dart, agregando compatibilidad para acceder a referencias de objetos de forma segura sin activar excepciones de referencias nulas. Hoy le ofrecemos una forma de obtener una vista previa del análisis estático de seguridad nula. Veamos un pequeño ejemplo motivador:

void main () { 
Persona ('Larry', cumpleaños: DateTime (1973, 03, 26)). describe ();
Persona ('Sergey'). Describe ();
} clase Persona {
String firstName;
Fecha y hora de cumpleaños;
Persona (this.firstName, {this.birthday}); void describe () {
print (firstName);
int birthyear = birthday? .year;
print ('Born $ {DateTime.now (). year - birthyear} hace años');
}
}

Si ejecutamos este código, se bloquea con una excepción de puntero nulo al describir a la segunda persona, porque esa persona no tiene un cumpleaños establecido. Cometimos un error de codificación: si bien anticipamos que algunas personas tienen cumpleaños desconocidos al hacer que el campo birthday sea opcional en el constructor y al probar un cumpleaños nulo birthday?.year, olvidamos manejar el caso donde birthyeares nulo.

Intente pegar este código en la nueva área de juegos de seguridad nula , una compilación especial de DartPad que contiene una vista previa técnica de la parte de análisis estático de la función de seguridad nula. Sin siquiera ejecutar el código, podemos ver tres problemas:

DartPad con seguridad nula que muestra tres errores de análisis relacionados con nulos

Al corregir estos errores de análisis, podemos comenzar a aprovechar la seguridad nula. Intente realizar las siguientes ediciones en el playground de seguridad nula (eventualmente obteniendo este código seguro ):

  1. Para declarar que el cumpleaños puede ser nulo, cambie
    DateTime birthdayaDateTime? birthday
  2. Para declarar que el nacimiento puede ser nulo cuando el cumpleaños es nulo, cambie
    int birthyearaint? birthyear
  3. Envuelva la última llamada impresa en una prueba nula:
    if (birthyear != null) {…}

Esperamos que este ejemplo le brinde una idea de la experiencia que queremos con seguridad nula. Como se mencionó, este playground es solo una vista previa técnica temprana de parte de la seguridad nula, ya que se está construyendo. Estamos trabajando arduamente para completar una primera versión beta de seguridad nula en Dart SDK. Esto es en lo que estamos trabajando para beta:

  1. Completar la implementación completa de referencias anulables y no anulables.
  2. Integrar la seguridad nula en la inferencia de tipos y la promoción inteligente de Dart (por ejemplo, permitir el acceso seguro a una variable anulable después de una asignación o verificación nula)
  3. Portar las bibliotecas principales de Dart para declarar qué tipos son anulables y cuáles no anulables
  4. Agregar una herramienta de migración, que puede automatizar la mayoría de las tareas de actualización para portar aplicaciones y paquetes Dart

Una vez que se complete este trabajo, lo pondremos a disposición en un SDK beta y podrá comenzar a aprovechar la función en sus aplicaciones y paquetes. También planeamos mantener actualizado el área de juegos de seguridad nula con nuevas características a medida que se implementan.

Si bien estamos seguros de que muchos desarrolladores querrán usar la seguridad nula tan pronto como esté disponible, puede migrar cuando sea conveniente, optando por la función cuando esté listo. Las bibliotecas y los paquetes que aún no han optado por la función podrán depender de las bibliotecas que hayan optado , y viceversa.

Tendremos más que decir sobre la seguridad nula en los próximos meses, incluyendo consejos más detallados sobre cómo prepararse para la transición.

Me gusta 👍 paquetes en pub.dev

También se lanzará hoy en pub.dev una nueva función Me gusta para paquetes. Esto introduce una nueva “señal humana” para indicar qué paquetes le gustan. Para dar me gusta a un paquete, simplemente haga clic en el icono de pulgar hacia arriba que se encuentra junto a la información detallada del paquete:

Página de detalles del paquete pub.dev con el nuevo botón de votación Me gusta

Actualmente, no tenemos en cuenta el número de Me gusta en nuestro modelo de puntuación general, pero planeamos hacerlo en una versión posterior. También planeamos darle a nuestra IU de búsqueda general y a las páginas de la lista una revisión visual que resaltará la posibilidad de un paquete.

Gracias

En nombre del equipo Dart, nos gustaría agradecerte y a todos en la comunidad Dart por su continuo apoyo. Continúa ofreciéndonos comentarios y participa en las discusiones y comunidades de Dart . No seríamos un proyecto de código abierto que funcione bien sin el apoyo que recibimos de la comunidad Dart.

2019 ha sido un año increíblemente emocionante para Dart, pero no nos detendremos aquí. Tenemos planes audaces para el 2020, que incluyen el envío de versiones estables de características como dart: ffi y null safety e introducir nuevas características. Te invitamos a comenzar a usar Dart 2.7 hoy. Está disponible en dart.dev , en la versión Flutter 1.12 de hoy y en el recientemente rediseñado DartPad .

--

--