En Perl, ¿por qué la construcción ''while(<HANDLE>){...} `no localiza` $_`?
language-design while-loop (4)
Como nota al margen, solo escribimos while(<$fh>)
porque Perl no tiene iteradores reales. Si Perl tuviera los iteradores adecuados, <$fh>
devolvería uno. usaría eso para iterar una línea a la vez en lugar de agrupar todo el archivo en una matriz. No habría necesidad de while(<$fh>)
o los casos especiales asociados con él.
¿Cuál fue la razón de diseño (o técnica) para que Perl no localice automáticamente $_
con la siguiente sintaxis:
while (<HANDLE>) {...}
Que se reescribe como:
while (defined( $_ = <HANDLE> )) {...}
Todas las otras construcciones que escriben implícitamente en $_
hacen de manera localizada ( for/foreach
, map
, grep
), pero con while
, debe localizar explícitamente la variable:
local $_;
while (<HANDLE>) {...}
Mi conjetura es que tiene algo que ver con el uso de Perl en el modo "Super-AWK" con interruptores de línea de comando, pero eso podría estar mal.
Entonces, si alguien sabe (o mejor aún, estuvo involucrado en la discusión del diseño del lenguaje), ¿podría compartir con nosotros el razonamiento detrás de este comportamiento? Más específicamente, ¿por qué permitir que el valor de $_
persista fuera del bucle se considera importante, a pesar de los errores que puede causar (lo cual tiendo a ver en todo el lugar en SO y en otro código de Perl)?
En caso de que no quede claro lo anterior, la razón por la cual $_
debe localizarse con while
se muestra en este ejemplo:
sub read_handle {
while (<HANDLE>) { ... }
}
for (1 .. 10) {
print "$_: /n"; # works, prints a number from 1 .. 10
read_handle;
print "done with $_/n"; # does not work, prints the last line read from
# HANDLE or undef if the file was finished
}
Desde el thread en perlmonks.org:
Hay una diferencia entre
foreach
ywhile
porque son dos cosas totalmente diferentes.foreach
siempre se asigna a una variable cuando se repite en una lista, mientraswhile
normalmente no lo hace. Es solo quewhile (<>)
es una excepción y solo cuando hay un solo operador Diamond, hay una asignación implícita a$_
.
Y también:
Una posible razón por la
while(<>)
no localiza implícitamente$_
como parte de su magia es que a veces desea acceder al último valor de$_
fuera del bucle.
Especulación: Porque for
y foreach
son iteradores y valores de bucle sobre, mientras que while
opera en una condición. En el caso de while (<FH>)
la condición es que los datos se leyeron del archivo. El <FH>
es lo que escribe a $_
, no el while
. La prueba defined()
implícita defined()
es solo una opción para evitar que un código ingenuo termine el ciclo en una lectura de valor falso.
Para otras formas de bucles while, por ejemplo, while (/foo/)
no querría localizar $_
.
Si bien estoy de acuerdo en que sería bueno que si while (<FH>)
$_
localizado, tendría que ser un caso muy especial, que podría causar otros problemas al reconocer cuándo activarlo y cuándo no, muy parecido a las reglas para <EXPR>
distingue es una lectura de identificador o una llamada a glob
.
Sencillamente, while
nunca se localiza. Ninguna variable está asociada con una construcción de while
, por lo que ni siquiera tiene nada que localizar.
Si cambia alguna variable en la expresión de bucle while o en un cuerpo de bucle while, es responsabilidad suya realizar un alcance adecuado.