Dart 2.17: Productividad e integración
Características del lenguaje. Herramientas de productividad. Integración de plataforma más profunda y amplia.
Hoy en el Google I/O, anunciamos un nuevo SDK de Dart, versión 2.17. Esta versión se basa en nuestros temas centrales de productividad líder y portabilidad de plataformas. Ofrece nuevas características del lenguaje: enums con soporte de miembros, reenvío mejorado de parámetros a superclases, y mayor flexibilidad para parámetros nombrados. Hemos mejorado las herramientas con una nueva versión principal de
package:lints — nuestra herramienta para verificar que el código Dart cumple con nuestras mejores prácticas — y una amplia actualización de la documentación de las API de las bibliotecas principales con ejemplos de código enriquecidos. Para una mejor integración con plataformas, tenemos nuevas plantillas para usar
dart:ffi (interoperabilidad nativa con C) en plugins de Flutter, soporte experimental para procesadores RISC-V, y soporte para firmar ejecutables de macOS y Windows.
Nuevas características del lenguaje para mejorar la productividad
#Evolucionamos constantemente el lenguaje Dart para hacerte más productivo — tanto añadiendo nuevas características como haciendo mejoras a las características existentes. Dart 2.17 añade un importante soporte nuevo para miembros en enums, refina cómo puedes usar argumentos nombrados en constructores, y hace que el código para reenviar parámetros a superclases sea mucho menos verboso y repetitivo.
Enums mejorados con miembros
#Los enums son geniales para representar un conjunto discreto de estados. Por ejemplo, podríamos modelar el agua como enum Water { frozen, lukewarm, boiling }. Pero ¿qué pasa si queremos añadir algunos métodos al
enum — por ejemplo, para convertir cada uno de los estados a una temperatura, y soportar la conversión del
enum a un String? Podríamos usar métodos de extensión para añadir un método
waterToTemp(), pero tendríamos que tener cuidado de mantenerlo sincronizado con el enum. Para la conversión a String
preferiríamos sobrescribir toString(), pero eso no estaba soportado.
Con Dart 2.17 ahora tenemos soporte general para miembros en enums. Eso significa que podemos añadir campos que contienen estado, constructores que establecen ese estado, métodos con funcionalidad, e incluso sobrescribir miembros existentes. Muchos de ustedes han estado solicitando esta capacidad; fue nuestro tercer issue más votado en el tracker del lenguaje.
Para nuestro ejemplo del agua, podemos añadir un campo int que contenga la temperatura y un constructor por defecto que tome un
int:
enum Water {
…
final int tempInFahrenheit;
const Water(this.tempInFahrenheit);
}
Para asegurar que el constructor sea llamado cuando se crea el enum, necesitamos invocarlo para cada valor del
enum:
enum Water {
frozen(32),
lukewarm(100),
boiling(212);
…
}
Para soportar la conversión a String, simplemente sobrescribimos toString, que los enums
heredan de Object:
[@override](http://twitter.com/override)
String toString() => "The $name water is $tempInFahrenheit F.";
Y con eso, tienes un enum completo que puede ser fácilmente instanciado y sobre el que puedes invocar métodos:
void main() {
print(Water.frozen); // Prints “The frozen water is 32 F.”
}
Un ejemplo completo de estos dos enfoques se ilustra a continuación; nos parece que la nueva versión de Dart 2.17 es mucho más fácil de leer y mantener.
Super initializers
#Cuando tienes una jerarquía de herencia de clases, un patrón común es pasar algunos parámetros del constructor al constructor de la superclase. Para hacer eso, la subclase necesita 1) listar cada parámetro en su propio constructor, y 2) invocar el super constructor con esos parámetros. Eso genera código boilerplate: mucha repetición, haciendo el código más difícil de leer y más molesto de mantener.
Varios miembros de la comunidad Dart ayudaron a hacer esto posible. El usuario de GitHub @roy-sianez presentó un issue del lenguaje sobre esto hace aproximadamente medio año; sugiriendo algo similar a lo que el usuario de GitHub @apps-transround había sugerido anteriormente: que podríamos resolver esto introduciendo una nueva construcción para expresar que un parámetro fue especificado en la superclase. Nos pareció una excelente idea, así que esto se ha añadido a Dart 2.17. Como puedes ver en el siguiente ejemplo, esto es especialmente relevante para el código de widgets de Flutter. De hecho, cuando aplicamos la nueva característica al framework de Flutter, vimos una reducción total de casi dos mil líneas de código!
Argumentos nombrados en cualquier lugar
#Por último, hemos refinado cómo funcionan los argumentos nombrados cuando invocas un método. Anteriormente, estos tenían que aparecer al final en la lista de argumentos del método. Esto era molesto en los casos donde preferías colocar un argumento posicional al final para hacer el código más legible. Por ejemplo, mira la siguiente invocación del constructor
List<T>.generate — antes, el argumento growable tenía que colocarse al final, haciendo fácil pasarlo por alto debajo del gran argumento posicional que contiene el generador mismo. Ahora puedes ordenarlos como prefieras, permitiéndote colocar los pequeños argumentos nombrados primero y el generador al final.
Para más ejemplos de estas tres características en acción, consulta nuestros ejemplos actualizados de enums, super initializers, y parámetros nombrados.
Herramientas de productividad
#Continuando con el tema de productividad, tenemos varias mejoras en nuestras herramientas principales.
En Dart 2.14 introdujimos package:lints, que funciona con el analyzer de Dart para ayudarte a escribir código Dart que previene errores y usa un estilo canónico que permite revisiones de código más efectivas. Desde entonces, varios lints nuevos se han hecho disponibles en el analyzer, los cuales hemos evaluado cuidadosamente y de ahí seleccionado
diez nuevos lints para todo el código Dart, y
dos nuevos lints
específicamente para código Flutter. Estos incluyen lints para asegurar que tus imports estén incluidos en tu archivo pubspec, prevenir el uso indebido de verificaciones de null en parámetros de tipo, y asegurar un estilo consistente para las propiedades child. Puedes actualizar a los nuevos lints con un simple comando:
-
Para paquetes Dart:
dart pub upgrade —-major-versions lints -
Para paquetes Flutter:
flutter pub upgrade —-major-versions flutter_lints
Los SecureSockets se usan comúnmente para habilitar sockets TCP asegurados con TLS y SSL. Antes de Dart 2.17, depurar estos sockets durante el desarrollo era complicado, ya que no había forma de inspeccionar el tráfico de datos seguro. Ahora hemos añadido soporte para especificar un archivo
keyLog. Cuando se especifica, se añade una línea de texto en el NSS Key Log Format
al archivo cuando se intercambian nuevas claves TLS con el servidor. Esto permite que herramientas analizadoras de tráfico de red (como
Wireshark) descifren el contenido enviado a través del socket. Para más detalles, consulta la documentación de la API para
SecureSocket.connect().
La documentación de API generada por la herramienta dart doc es un recurso crítico para la mayoría de los desarrolladores de Dart que aprenden nuevas API. Aunque nuestras
API de bibliotecas principales han tenido durante mucho tiempo descripciones textuales ricas, muchos desarrolladores nos han dicho que prefieren aprender API leyendo código de ejemplo que usa la API. Con Dart 2.17, hemos revisado completamente todas las bibliotecas principales importantes, añadiendo código de ejemplo a las 200 páginas más vistas, de modo que ahora tienen código de ejemplo completo. Como ejemplo, compara la documentación de dart:convert en
Dart 2.16 con la página actualizada para
Dart 2.17; esperamos que esto haga la documentación mucho más fácil de consumir.
Las ganancias de productividad no solo vienen cuando añadimos nuevas características a nuestra plataforma, sino también cuando limpiamos nuestro stack y eliminamos características que ya no se usan. Esto ayuda a mantener nuestra superficie pequeña, lo cual es crítico especialmente para los nuevos desarrolladores. Con este fin, hemos eliminado
231 líneas de código deprecado de la biblioteca
dart:io — si todavía estás usando estas API deprecadas, puedes actualizar a sus reemplazos con
dart fix. También hemos continuado nuestro esfuerzo para eliminar
herramientas CLI de Dart deprecadas, esta vez eliminando la herramienta
dartdoc (usa dart doc en su lugar), y la herramienta pub (usa dart pub
o flutter pub).
Ampliando nuestra integración y soporte de plataformas
#Un segundo tema central es la integración y soporte de plataformas. Dart es un verdadero lenguaje multiplataforma. Aunque ya soportamos una amplia gama de plataformas, estamos evolucionando constantemente para asegurar que puedas integrarte profundamente con cada plataforma soportada, y también para soportar plataformas emergentes.
Dart FFI — nuestro mecanismo principal para interoperabilidad con código C/nativo
— es una forma popular de integrar código Dart con código nativo existente de la plataforma. En Flutter, esto puede ser una excelente forma de construir
plugins que usen API nativas de la plataforma anfitriona (como las API win32 de Windows). En Dart 2.17 y Flutter 3, hemos añadido plantillas a la herramienta
flutter para que ahora puedas crear fácilmente FFI Plugins que tienen una API Dart respaldada por llamadas dart:ffi
a código nativo. Para más detalles, consulta la página actualizada sobre desarrollo de paquetes y plugins
en flutter.dev.
Para habilitar el uso de FFI en plataformas que tienen tipos específicos de su ABI (interfaz binaria de aplicación), FFI ahora soporta tipos específicos de ABI. Por ejemplo, ahora puedes usar
Long (long
en C) para representar correctamente un entero largo con un tamaño específico de ABI, que podría ser de 32 bits o 64 bits dependiendo de la arquitectura de la CPU. Para la lista completa de tipos soportados, consulta la lista de “Implementers” en la página de la API de
AbiSpecificInteger.
Al integrarse profundamente con plataformas nativas usando Dart FFI, a veces necesitas alinear la limpieza de memoria u otros recursos (puertos, archivos, etc.) asignados por Dart y el código nativo. Esto ha sido históricamente muy complicado, ya que Dart es un lenguaje con recolección de basura que maneja la limpieza automáticamente. Dart 2.17 resuelve esto introduciendo el concepto de un Finalizer, que incluye una interfaz marcadora
Finalizable para “etiquetar” objetos que no deberían ser finalizados o descartados demasiado pronto, y una clase
NativeFinalizer que puede adjuntarse a un objeto Dart para proporcionar un callback que se ejecuta cuando el objeto está a punto de ser recolectado por el garbage collector. Juntos, estos permiten ejecutar código de limpieza tanto en código nativo como en código Dart. Para más detalles, consulta la descripción y el ejemplo en la documentación de la API para
NativeFinalizer, o la documentación para
WeakReferences
y Finalizer
para soporte similar en código Dart regular.
Nuestro soporte para compilar Dart a código nativo es un habilitador clave para que las apps de Flutter tengan un excelente rendimiento de inicio y un renderizado rápido. Un segundo caso de uso es la capacidad de compilar Dart a ejecutables con
dart compile. Estos ejecutables pueden funcionar de forma independiente en cualquier máquina sin necesidad de tener el SDK de Dart instalado. Otra nueva capacidad en Dart 2.17 es el soporte para
firmado de ejecutables, lo cual habilita el despliegue en Windows y macOS donde el firmado suele ser requerido.
También continuamos ampliando nuestro conjunto de plataformas soportadas manteniéndonos a la vanguardia de las nuevas plataformas emergentes.
RISC-V es un nuevo conjunto de instrucciones innovador para procesadores. RISC-V International, una organización global sin fines de lucro, es dueña de la especificación RISC-V, haciendo que el conjunto de instrucciones sea libre y abierto. Sigue siendo una plataforma emergente, pero estamos emocionados con su potencial, por lo que nuestra versión Linux
2.17.0–266.1.beta (o posterior desde nuestro canal beta)
incluye soporte experimental para ella. Nos encantaría escuchar tu feedback, así que por favor abre un issue
o publica sobre tu experiencia!
¡Comienza con Dart 2.17!
#Esperamos que la versión de hoy de Dart 2.17 te entusiasme, mejore tu productividad, y habilite aún más integración de plataformas para tus apps. Para comenzar, puedes descargar directamente la versión de Dart 2.17, o obtenerla integrada como parte de la versión del SDK de Flutter 3 de hoy.
También te invitamos a revisar el nuevo contenido que hemos hecho disponible para Google I/O!