Skip to content

Latest commit

 

History

History
454 lines (327 loc) · 16.9 KB

perllexwarn.pod

File metadata and controls

454 lines (327 loc) · 16.9 KB

NOMBRE

perllexwarn - Advertencias léxicas de Perl

DESCRIPCIÓN

El pragma use warnings permite controlar con precisión qué advertencias han de ser habilitadas en un programa Perl. Es una alternativa más flexible, tanto para la opción de la línea de comandos -w como para la variable de Perl equivalente, $^W.

Este pragma funciona igual que el pragma strict. Esto significa que el ámbito del pragma warning está limitado al bloque que lo alberga. También significa que el ajuste para este pragma no se escapará a través de los archivos (a través de use, require o do). Esto permite a los autores, de forma independiente, definir el grado de control de advertencia que se aplicará a su módulo.

De forma predeterminada, las advertencias opcionales están desactivadas, por lo que cualquier código heredado que no intente controlar las advertencias, funcionará sin problemas.

Todas las advertencias están habilitadas en un bloque, usando cualquiera de estas formas:

use warnings;
use warnings 'all';

Del mismo modo todos las advertencias se desactivan en un bloque, usando cualquiera de estas formas:

no warnings;
no warnings 'all';

Por ejemplo, considere el código siguiente:

use warnings;
my @a;
{
    no warnings;
        my $b = @a[0];
}
my $c = @a[0];

El código en el bloque que lo alberga tiene las advertencias activadas, pero el bloque más interno las ha desactivado. En este caso, eso significa que la asignación al escalar $c se disparará la advertencia "Scalar value @a[0] better written as $a[0]" ("Valor escalar @a[0] queda mejor escrito como $a[0]"), pero la asignación al escalar $b, no lo hará.

Advertencias predeterminadas y Advertencias opcionales

Antes de la introducción de las advertencias léxicas, Perl tenía dos clases de advertencias: obligatorias y opcionales.

Como su nombre indica, si su código disparó una advertencia obligatoria, obtendrá una advertencia tanto si lo quería como si no. Por ejemplo, el código siguiente, siempre producirá una advertencia "isn't numeric" ("no es numérico") sobre el "2:".

my $a = "2:" + 3;

Con la introducción de las advertencias léxicas, las advertencias obligatorias ahora se han convertido en advertencias predeterminadas. La diferencia es que a pesar de que las advertencias que previamente eran obligatorias siguen estando activadas por defecto, pueden ser activadas o desactivadas posteriormente con el pragma warning léxico. Por ejemplo, en el código siguiente, una advertencia "isn't numeric" ("no es numérico") sólo será emitida para la variable $a.

my $a = "2:" + 3;
no warnings;
my $b = "2:" + 3;

Tenga en cuenta que ni la opción -w ni la $^W pueden ser utilizados para activar/desactivar las advertencias predeterminadas. Siguen siendo obligatorias, en este caso.

Qué hay de malo con -w y $^W

Aunque es muy útil, el gran problema con el uso de -w en la línea de comandos para activar las advertencias, es que es un "todo o nada". Tome el caso típico de cuando escribe un programa en Perl. Hay partes del código que va a escribir usted mismo, pero es muy probable que vaya a usar módulos Perl pre-escritos. Si utiliza la opción -w, en este caso, lo que estará haciendo es activar las advertencias en partes de código que usted no ha escrito.

Del mismo modo, usar $^W para deshabilitar o habilitar bloques de código es, fundamentalmente, erróneo. Para empezar, digamos que desea deshabilitar las advertencias en un bloque de código. Se podría esperar que esto sea suficiente para hacer el truco:

{
    local ($^W) = 0;
         my $a =+ 2;
         my $b; chop $b;
}

Cuando este código se ejecuta con la opción -w, una advertencia se produce para $a en la línea: "Reversed += operator" ("operador += invertido").

El problema es que Perl tiene advertencias tanto en tiempo de compilación como en tiempo de ejecución. Para desactivar las advertencias en tiempo de compilación, necesita volver a escribir el código así:

{
    BEGIN { $^W = 0 }
         my $a =+ 2;
         my $b; chop $b;
}

El otro gran problema con $^W es la forma en que, usted, sin darse cuenta, puede cambiar la configuración de advertencias en los lugares más inesperados de su código. Por ejemplo, cuando el código siguiente se ejecuta (sin la opción -w), la segunda llamada a hazlo disparará una advertencia "Use of uninitialized value" ("Uso de un valor no inicializado"), mientras que el primero no.

sub hazlo
{
    my $b; chop $b;
}

hazlo();

{
    local ($^W) = 1;
    hazlo()
}

Este es un efecto secundario de $^W al ser dinámicamente activado en un cierto ámbito.

Las advertencias léxicas superan estas limitaciones, permitiendo un mayor control sobre dónde las advertencias pueden o no tropezar.

Controlando las advertencias desde la línea de comandos

Hay tres opciones de línea de comandos que pueden ser utilizadas para controlar cuándo las advertencias deben ser (o no) producidas:

-w

Esta es la opción actual. Si el pragma léxico warning no es utilizado en ninguna parte de su código, o en ninguno de los módulos que está usando, esta opción activará las advertencias en todas partes. Ver "Compatibilidad con versiones anteriores" para más información sobre cómo esta opción interactúa con las advertencias léxicas.

-W

Si la opción -W es utilizada en la línea de comandos, activará todas las advertencias de todo el programa, independientemente de si las advertencias fueron inhabilitadas de forma local utilizando no warnings o $^W =0. Esto incluye todos los archivos que hayan sido incluidos a través de use, require o do. Piense en ello como el equivalente Perl del comando "lint".

-X

Hace exactamente lo contrario a la opción -W, es decir, desactiva todas las advertencias.

Compatibilidad con versiones anteriores

Si está acostumbrado a trabajar con una versión de Perl anterior a la introducción de las advertencias con alcance léxico, o si tiene código que utiliza tanto las advertencias léxicas y $^W, esta sección describirá la forma en que interactúan.

Cómo interactúan las advertencias léxicas con -w/$^W:

  1. Si no usa ninguna de las tres opciones de línea de comandos (-w, -W o -X) que controlan las advertencias, y ni $^W o el pragma warnings son usados, entonces son activadas las advertencias predeterminadas, y desactivadas las advertencias opcionales. Esto significa que el código heredado que no trate de controlar a las advertencias, funcionará sin problemas.

  2. La opción -w sólo establece la variable global $^W, como en 5.005. Esto significa que cualquier código heredado que en la actualidad se base en la manipulación de $^W para controlar el comportamiento de las advertencias, seguirá funcionando tal cual.

  3. Aparte de que ahora es un valor booleano, la variable $^W funciona exactamente de la misma y horrible forma global y descontrolada, excepto que no puede activar/desactivar las advertencias predeterminadas.

  4. Si una parte del código está bajo el control del pragma warnings, tanto la variable $^W como la opción -w serán ignoradas para el ámbito del warning léxico.

  5. La única manera de anular un ajuste de las advertencias léxicas es con las opciones -W o -X de la línea de comandos.

El efecto combinado de 3 y 4 es que permitirá que el código que utiliza el pragma warnings controle el comportamiento de las advertencias del código de tipo $^W (utilizando un local $^W=0) si realmente lo quiere así, pero no al contrario.

Jerarquía de categorías

Una jerarquía de "categorías" han sido definidas para permitir que grupos de advertencias sean activados/desactivados de forma independiente.

La jerarquía actual es la siguiente:

all -+
     |
     +- closure
     |
     +- deprecated
     |
     +- exiting
     |
     +- glob
     |
     +- io -----------+
     |                |
     |                +- closed
     |                |
     |                +- exec
     |                |
     |                +- layer
     |                |
     |                +- newline
     |                |
     |                +- pipe
     |                |
     |                +- unopened
     |
     +- imprecision
     |
     +- misc
     |
     +- numeric
     |
     +- once
     |
     +- overflow
     |
     +- pack
     |
     +- portable
     |
     +- recursion
     |
     +- redefine
     |
     +- regexp
     |
     +- severe -------+
     |                |
     |                +- debugging
     |                |
     |                +- inplace
     |                |
     |                +- internal
     |                |
     |                +- malloc
     |
     +- signal
     |
     +- substr
     |
     +- syntax -------+
     |                |
     |                +- ambiguous
     |                |
     |                +- bareword
     |                |
     |                +- digit
     |                |
     |                +- illegalproto
     |                |
     |                +- parenthesis
     |                |
     |                +- precedence
     |                |
     |                +- printf
     |                |
     |                +- prototype
     |                |
     |                +- qw
     |                |
     |                +- reserved
     |                |
     |                +- semicolon
     |
     +- taint
     |
     +- threads
     |
     +- uninitialized
     |
     +- unpack
     |
     +- untie
     |
     +- utf8 ---------+
     |                |
     |                +- surrogate
     |                |
     |                +- non_unicode
     |                |
     |                +- nonchar
     |
     +- void

Al igual que en el pragma "strict", ninguna de estas categorías pueden ser combinadas

use warnings qw(void redefine);
no warnings qw(io syntax untie);

También como en el pragma "strict", si hay más de una instancia del pragma warnings en un determinado ámbito, el efecto acumulativo es aditivo.

use warnings qw(void); # solo están activas las advertencias "void"
...
use warnings qw(io);   # solo activas advertencias "void" y "io"
...
no warnings qw(void);  # solo activas advertencias "io"

Para determinar a qué categoría ha sido asignada una advertencia específica, vea perldiag.

Nota: En Perl 5.6.1, la categoría de las advertencias léxicas deprecated ("obsoleto") era una sub-categoría de la categoría syntax ("sintaxis"). Ahora es una categoría de nivel superior por derecho propio.

Advertencias fatales

La presencia de la palabra "FATAL" en la lista de categorías, escalará cualquier advertencia detectada a partir de las categorías especificadas en el ámbito léxico, a errores fatales. En el código siguiente, el uso de time, length y join pueden producir todos ellos una advertencia "Useless use of xxx in void context" ("Uso inútil de xxx en contexto vacío").

use warnings;

time;

{
    use warnings FATAL => qw(void);
    length "abc";
}

join "", 1,2,3;

print "hecho\n";

Cuando se ejecuta se produce esta salida

Useless use of time in void context at fatal line 3.
Useless use of length in void context at fatal line 7.  

El ámbito donde length es utilizado ha escalado la categoría de advertencias void, a un error grave, por lo que el programa termina de inmediato cuando se encuentra con la advertencia.

Para activar de forma explícita una advertencia "FATAL" solo tiene que desactivar la advertencia a la que estaba asociada. Así, por ejemplo, para desactivar la advertencia "void" del ejemplo anterior, cualquiera de los siguientes hará el truco:

no warnings qw(void);
no warnings FATAL => qw(void);

Si desea degradar una advertencia que ha sido escalada a un error fatal, de nuevo a una advertencia normal, puede usar la palabra clave "NONFATAL". Por ejemplo, el código siguiente, promocionará todas las advertencias en errores fatales, a excepción de los de la categoría "syntax".

use warnings FATAL => 'all', NONFATAL => 'syntax';

Reportando advertencias desde un módulo

El pragma warnings proporciona una serie de funciones que son útiles para los autores de módulos. Estos son utilizados cuando desea informar de una advertencia específica del módulo, a un módulo que lo llama, y que tenga las advertencias activadas por medio del pragma warnings.

Considere el módulo MiMod::Abc siguiente.

package MiMod::Abc;

use warnings::register;

sub open {
    my $ruta = shift;
    if ($ruta !~ m#^/#) {
        warnings::warn("cambiando ruta relativa a /var/abc")
            if warnings::enabled();
        $ruta = "/var/abc/$ruta";
    }
}

1;

La llamada a warnings::register creará una nueva categoría de advertencias llamada "MiMod::Abc", es decir, el nuevo nombre de la categoría coincide con el nombre del paquete actual. La función open en el módulo mostrará un mensaje de advertencia si se da una ruta relativa como parámetro. Estas advertencias sólo se mostrarán si el código que utiliza MiMod::Abc realmente ha activado el pragma warnings, como se indica a continuación.

use MiMod::Abc;
use warnings 'MiMod::Abc';
...
abc::open("../fred.txt");

También es posible comprobar si las categorías pre-definidas de advertencias están establecidas en el módulo que lo llama, con la función warnings::enabled. Considere el siguiente fragmento de código:

package MiMod::Abc;

sub open {
    warnings::warnif("deprecated", 
                     "open es obsoleto, use new en su lugar");
    new(@_);
}

sub new
...
1;

La función open ha quedado obsoleta, por lo que contiene código que muestra un mensaje de advertencia cada vez que el módulo que la llama tiene (al menos) la categoría de las advertencias "deprecated" habilitada. Algo como esto, por ejemplo.

use warnings 'deprecated';
use MiMod::Abc;
...
MiMod::Abc::open($archivo);

En realidad, se debe usar, tanto la función warnings::warn o la warnings::warnif para mostrar el mensaje de la advertencia. Esto es debido a que pueden hacer uso de la característica que permite a las advertencias ser escaladas a errores fatales. Así, en este caso

use MiMod::Abc;
use warnings FATAL => 'MiMod::Abc';
...
MiMod::Abc::open('../fred.txt');

la función warnings::warnif lo detectará y morirá después de mostrar el mensaje de advertencia.

Las tres funciones de advertencia, warnings::warn, warnings::warnif y warnings::enabled pueden, opcionalmente, tomar una referencia a un objeto en lugar de un nombre de categoría. En este caso, las funciones utilizarán el nombre de la clase del objeto como la categoría de las advertencias.

Considere este ejemplo:

package Original;

no warnings;
use warnings::register;

sub new
{
    my $clase = shift;
    bless [], $clase;
}

sub check
{
    my $self = shift;
    my $valor = shift;

    if ($valor % 2 && warnings::enabled($self))
      { warnings::warn($self, "Los números impares son inseguros") }
}

sub hazlo
{
    my $self = shift;
    my $valor = shift;
    $self->check($valor);
    # ...
}

1;

package Derivado;

use warnings::register;
use Original;
our @ISA = qw( Original );
sub new
{
    my $clase = shift;
    bless [], $clase;
}


1;

El código siguiente hace uso de ambos módulos, pero sólo activa las advertencias de Derivado.

use Original;
use Derivado;
use warnings 'Derivado';
my $a = Original->new();
$a->hazlo(1);
my $b = Derivado->new();
$a->hazlo(1);

Cuando este código es ejecutado, sólo el objeto Derivado, $b, generará una advertencia.

Los números impares son inseguros at main.pl line 7

Nótese también que la advertencia es reportada en la línea donde es usado el objeto por primera vez.

Al registrar nuevas categorías de advertencias, puede proporcionar más nombres warnings::register, así:

package MiModulo;
use warnings::register qw(format precision);

...

warnings::warnif('MiModulo::format', '...');

VEA TAMBIÉN

warnings, perldiag.

AUTOR

Paul Marquess

POD ERRORS

Hey! The above document had some coding errors, which are explained below:

Around line 3:

Non-ASCII character seen before =encoding in 'léxica>'. Assuming UTF-8