viernes, 22 de abril de 2011

Ya viene Perl 5.14

[English translation by google]

Hace unas horas salió el primer candidato a lo que será Perl 5.14 (ahora tenemos nuevas versiones de perl a cada rato :) en esta versión vienen nuevas características convenientes y algunas optimizaciones (sobre todo en windows).

Simetría entre arreglos, hashes y sus referencias

Esta es una de las características que más me gustan de Perl 5.14, pues simplifica la sintaxis cuando se manipulan referencias.

En el caso de los arreglos las primitivas como push, shift, unshift, pop y slice ahora aceptan referencias permitiendo cambiar el código:

  push @{ $arr->[1] }, 8
  $head = shift @{ $obj->arrayref }

por versiones más sencillas que ya no necesitan la dereferencia:

  push $arr->[1], 8
  $head = shift $obj->arrayref

lo que sin duda se ve mejor, sobre todo para los novatos.

Adicionalmnete keys, values y each trabajan con referecias a hashes, pero también trabajarán con arreglos y sus referecias, en este último caso se asumirán los valores del arreglo y las claves seran los índices enteros, así que se podrán hacer cosas como:

  for ( values $obj->arrayref ) { ... }
  for ( keys $obj->arrayref ) { ... }
  for ( keys %{$hoh->{genres}{artists}} ) {...}

En vez de:

  for ( @{ $obj->arrayref } ) { ... }
  for ( 0 .. @{ $obj->arrayref } ) { ... }
  for ( keys $hoh->{genres}{artists}    ) {...}

simplificando igualmente la sintaxis.
 
Una tabla de la documentación da varios ejemplos adicionales:

  |----------------------------+---------------------------|
  | Sintaxis tradicional       | Sintaxis compacta         |
  |----------------------------+---------------------------|
  | push @$arrayref, @stuff    | push $arrayref, @stuff    |
  | unshift @$arrayref, @stuff | unshift $arrayref, @stuff |
  | pop @$arrayref             | pop $arrayref             |
  | shift @$arrayref           | shift $arrayref           |
  | splice @$arrayref, 0, 2    | splice $arrayref, 0, 2    |
  | keys %$hashref             | keys $hashref             |
  | keys @$arrayref            | keys $arrayref            |
  | values %$hashref           | values $hashref           |
  | values @$arrayref          | values $arrayref          |
  | ($k,$v) = each %$hashref   | ($k,$v) = each $hashref   |
  | ($k,$v) = each @$arrayref  | ($k,$v) = each $arrayref  |
  |----------------------------+---------------------------|

Paquetes con bloques

Generalmente cuando se hace un script rápidamente, es más fácil declarar los paquetes (clases) en el mismo archivo, de igual manera es fácil caer en alguna trampa debido a que se tienen varios paquetes en un mismo entorno léxico, así cuando se declaran pragmas o variables léxicas, estas terminan afectando a otras clases o paquetes porque las declaraciones tienen como alcance léxico a todo el archivo, la manera estándar de evitar esto es declarando cada clase dentro de un bloque que acota su alcance léxico:

  {
    package Uno;
    ...
  }
  {
    package Dos;
    ...
  }
  ...

En perl 5.14 un paquete puede tener un bloque, haciendo que la construcción anterior se vea mejor:

  package Uno {
    ...
  }
  package Dos {
    ...
  }
  ...

Substitución no destructiva

Se implementa utilizando el modificador /r a una substitución, logrando que la variable ligada a la operación no sea afectada por la misma, en su lugar se retornará el valor modificado, así que el siguiente código:

  $result = do {
    my $ret = $text;
    $ret =~ s/pedro/juan/;
    $ret;
  };

Se podrá escribir de manera mas concisa en 5.14:

  $result = $text =~ s/pedro/juan/r

Este modificador también se agregó a la transliteración: tr///r

given devuelve valores

Siendo un fanático de Lisp esta característica me gustó, pues con frecuencia suelo simular (cond ...) en Perl haciendo:

my $result;
given ($val) {
    when(1) { $result = "uno" }
    when(2) { $result = "dos" }
    default { $result = undef }
}

En Perl 5.14 se podrá retornar un valor directamente, encapsulando toda la logica y sin necesidad de utilizar variables auxiliares fuera de la estructura:

my $result = do {
  given ($val) {
    when(1) { "uno" }
    when(2) { "dos" }
    default { undef }
} };

El do todavía es necesario ya que el parser de Perl todavía no reconoce la instrucción given como una expresión, aunque probablemente lo haga en el futuro.

\o{...} para incluir caracteres en código octal

Desde siempre Perl permite especificar caracteres como "\0376" sin embargo esta secuencia solo se permite para caracteres hasta 0777 (511), con la nueva secuencia se pueden especificar caracteres unicode con códigos mucho mayores, además el uso de esta secuencia permite eliminar confusiones con las retro-referencias (backreferences) en las expresiones regulares.

Mejoras en Unicode

Ahora se reconocen todo los nombres del unicode incluyendo abreviaturas y nombres de los caracteres de control, así que se pueden escribir caracteres como: "\N{ACK}", "\N{NBSP}", "\N{BEL}", entre otros. Estos nombres también se reconocen tanto en \N{} como en charnames.

Se introduce el pragma:  use feature "unicode_strings" que permite resolver la mayoría de las inconsistencias en la búsqueda de expresiones regulares con unicode, este pragma permitirá que el resultado funcione igual sin importar si la cadena es utf8 o no.

Se introducen los modificadores /d, /l y /u en las expresiones regulares:
  • /l para compilar la expresión regular como si estuviera en el contexto del pragma: use locale
  • /u para compilar la expresión regular como si estuviera en el contexto del pragma: use feature "unicode_strings"
  • /d permite anular los efectos de los pragmas: use locale y use feature "unicode_strings"
  • /a para interpretar la expresión como si fuera ASCII así \s encontrará exactamente los caracteres [ \f\n\r\t], \d encontrará exactamente [0123456789], \w encontrá exactamente los 63 caracteres [A-Za-z0-9_], y las clases de caracteres [[:posix:]] solamente conseguiran los caracteres apropiados del ASCII, también se afectan apropiadamente: \b y \B. Los complementos de estas clases consiguen cualquier cosa fuera de esto, como se debe.

Filehandle cargará automáticamente IO::File

Ahora cualquier filehandle se comportará como un IO::File, cuando se invoque un método inexistente para un filehandle perl cargará automáticamente IO::File, y reintentará la invocación nuevamente.

Mejoras en las funciones tipo printf

Ahora todas las funciones de la familia printf entienden los modificadores del estándar C90: "hh" (char), "z" (size_t), and "t" (ptrdiff_t), si además perl se compila con un compilador C99 también se interpretará el modificador "j" (intmax_t).

Introspección sobre el proceso de compilación

La nueva variable global ${^GLOBAL_PHASE} permitirá a los programas hacer introspección sobre la fase de compilación que se lleva a cabo, lo que permitirá en el futuro mejorar las capacidades de autoextensión del lenguaje.

Para aquellos que no esten al tanto de las capacidades de Perl, enterense que los programas en Perl pueden ejecutarse en tiempo de compilación para alterar el mismo proceso de compilación del programa, por eso aparecen características como está, que facilitará el desarrollo de nuevas extensiones al lenguaje.

Inyección de operaciones en la máquina virtual

Ahora se pueden registrar nuevas operaciones en la máquina virtual de perl, esto facilitará en el futuro la extensión de la máquina virtual con nuevas propiedades y operaciones.

Otras mejoras

Se optimizó la concatenación de cadenas de caracteres que pueden llegar a ser hasta 100 veces más rápidas en ciertas plataformas (como windows).

Se optimizó el uso de %+ y %- para programas que no los utilizan.

3 comentarios:

  1. Gracias por el artículo. Tengo que instalar 5.14 pronto para tratar estas nuevas características a mí mismo.

    ResponderEliminar
  2. La sustitución regresiva también la han puesto porque había muchas líneas de este tipo:

    (my $result = $text) =~ s/pedro/juan/;

    lo cual era complicado de entender para los novatos, pero de uso muy común para los experimentados (aparece en muchos módulos de CPAN, por ejemplo).

    Con la nueva opción /r, el código queda un poco más claro.

    ResponderEliminar
  3. Tienes un errorcito, donde dice
    for ( keys %{$hoh->{genres}{artists}} ) {...}
    quieres decir
    for ( keys $hoh->{genres}{artists} ) {...}

    y viceversa.

    Me entero de esta mejora.
    Para poderla usar, cómo recomiendas que uno verifique la versión?
    mis scripts empiezan así: #!/usr/bin/perl -w\nuse strict;
    Cómo se verifica que la versión es 5.14 o más reciente?

    ResponderEliminar