perl integer boolean

¿Qué significa "0 pero verdadero" en Perl?



integer boolean (14)

¿Puede alguien explicar qué significa exactamente la cadena "0 pero verdadero" en Perl? Por lo que entiendo, es igual a cero en una comparación de enteros, pero se evalúa como verdadero cuando se usa como booleano. ¿Es esto correcto? ¿Es este un comportamiento normal del idioma o se trata de una cadena especial tratada como un caso especial en el intérprete?


"0 pero verdadero" es una cadena como cualquier otra, pero debido a la sintaxis de perl puede servir un propósito útil, a saber, devolver un entero de una función sin que el resultado sea "falso" (a los ojos de perl).

Y la cadena no necesita ser "0 sino verdadera". "0 pero falso" sigue siendo "verdadero" en el sentido booleano.

considerar:

if(x) for x: yields: 1 -> true 0 -> false -1 -> true "true" -> true "false" -> true "0 but true" -> true int("0 but true") ->false

El resultado de todo esto es que puedes tener:

sub find_x()

y haga que este código pueda imprimir "0" como salida:

if($x = find_x) { print int($x) . "/n"; }


Acabo de encontrar una prueba de que la cadena "0 pero es verdadera" está incorporada en el intérprete, como algunas personas aquí ya respondieron:

$ strings /usr/lib/perl5/5.10.0/linux/CORE/libperl.so | grep -i true Perl_sv_true %-p did not return a true value 0 but true 0 but true


Además de lo que otros dicen, "0 but true" está incluido en una caja especial porque no advierte en el contexto numérico:

$ perl -wle ''print "0 but true" + 3'' 3 $ perl -wle ''print "0 but crazy" + 3'' Argument "0 but crazy" isn''t numeric in addition (+) at -e line 1. 3


Cosas que son falsas:

  • "" .
  • "0" .
  • Cosas que encadenan a esos.

"0 but true" no es uno de esos, así que no es falso.

Además, Perl devuelve "0 but true" donde se espera un número para indicar que una función tuvo éxito aunque devolvió cero. sysseek es un ejemplo de tal función. Dado que se espera que el valor se utilice como un número, Perl se codifica para que se considere un número. Como resultado, no se emiten advertencias cuando se usa como número, y looks_like_number("0 but true") devuelve true.

Se pueden encontrar otros "ceros verdaderos" en http://www.perlmonks.org/?node_id=464548 .


Cuando desee escribir una función que devuelva un valor entero, o falso o undef (es decir, para el caso de error), debe tener cuidado con el valor cero. Devolverlo es falso y no debería indicar la condición de error, por lo que devolver "0 pero verdadero" hace que la función devuelva el valor verdadero mientras aún pasa el valor cero cuando se hacen cálculos matemáticos.


El valor 0 but true es un caso especial en Perl. Aunque para tus meros ojos mortales, no parece un número, sabio y sabiendo todo, Perl entiende que realmente es un número.

Tiene que ver con el hecho de que cuando una subrutina Perl devuelve un valor 0, se supone que la rutina falló o devolvió un valor falso.

Imagina que tengo una subrutina que devuelve la suma de dos números:

die "You can only add two numbers/n" if (not add(3, -2)); die "You can only add two numbers/n" if (not add("cow", "dog")); die "You can only add two numbers/n" if (not add(3, -3));

La primera afirmación no morirá porque la subrutina devolverá un 1 . Eso es bueno. La segunda afirmación morirá porque la subrutina no podrá agregar vaca a perro .

¿Y la tercera afirmación?

Hmmm, puedo agregar 3 a -3 . Solo obtengo 0 , pero luego mi programa morirá a pesar de que la subrutina add funcionó.

Para solucionar esto, Perl considera 0 but true que es un número. Si mi subrutina de adición no devuelve solo 0 , sino 0, pero es cierto , mi tercera declaración funcionará.

¿Pero es 0 pero verdadero un cero numérico? Prueba estos:

my $value = "0 but true"; print qq(Add 1,000,000 to it: ) . (1_000_000 + $value) . "/n"; print "Multiply it by 1,000,000: " . 1_000_000 * $value . "/n";

Sí, es cero!

La subrutina de index es una pieza muy antigua de Perl y existía antes del concepto de 0, pero la verdad estaba alrededor. Se supone que se devuelve la posición de la subcadena ubicada en la cadena:

index("barfoo", "foo"); #This returns 3 index("barfoo", "bar"); #This returns 0 index("barfoo", "fu"); #This returns ...uh...

La última declaración devuelve un -1 . Lo que significa que si hice esto:

if ($position = index($string, $substring)) { print "It worked!/n"; } else { print "If failed!/n"; }

Como normalmente hago con las funciones estándar, no funcionaría. Si usara "barfoo" y "bar" como lo hice en la segunda declaración, la cláusula else se ejecutaría, pero si usara "barfoo" y "fu" como en la tercera, se ejecutaría la cláusula if . No es lo que quiero.

Sin embargo, si la subrutina de index devolvió 0 pero es verdadero para la segunda declaración y undef para la tercera declaración, mi cláusula if / else hubiera funcionado.


En un contexto entero, se evalúa a 0 (la parte numérica al principio de la cadena) y es cero. En un contexto escalar, es un valor no vacío, por lo que es cierto.

  • if (int("0 but true")) { print "zero"; }

    (ninguna salida)

  • if ("0 but true") { print "true"; }

    (imprime verdad)


Es el comportamiento normal del lenguaje. Citando la perlsyn del perlsyn :

El número 0 , las cadenas ''0'' y "" , la lista vacía () y undef son todos falsos en un contexto booleano. Todos los demás valores son verdaderos. Negación de un verdadero valor por ! o not devuelve un valor falso especial. Cuando se evalúa como una cadena, se trata como "" , pero como un número, se trata como 0 .

Debido a esto, debe haber una forma de devolver 0 desde una llamada del sistema que espera devolver 0 como un valor de retorno (exitoso), y dejar una forma de señalar un caso de falla al devolver un valor falso. "0 but true" sirve para ese propósito.


Está codificado en el código fuente de Perl, específicamente en Perl_grok_number_flags en numeric.c .

Al leer ese código, descubrí que la cadena "infinito" (no distingue mayúsculas y minúsculas) también pasa la prueba looks_like_number. Yo no había sabido eso.


La cadena `0 pero cierto '''' sigue siendo un caso especial:

for arg in "''0 but true''" "1.0*(''0 but true'')" / "1.0*(''0 but false'')" 0 1 "''''" "0.0" / "''false''" "''Ja''" "''Nein''" "''Oui''" / "''Non''" "''Yes''" "''No''" ;do printf "%-32s: %s/n" "$arg" "$( perl -we '' my $ans=eval $ARGV[0]; $ans=~s/^(Non?|Nein)$//; if ($ans) { printf "true: |%s|/n",$ans } else { printf "false: |%s|", $ans };'' "$arg" )" done

da lo siguiente: (nota la `` advertencia ''''!)

''0 but true'' : true: |0 but true| 1.0*(''0 but true'') : false: |0| Argument "0 but false" isn''t numeric in multiplication (*) at (eval 1) line 1. 1.0*(''0 but false'') : false: |0| 0 : false: |0| 1 : true: |1| '''' : false: || 0.0 : false: |0| ''false'' : true: |false| ''Ja'' : true: |Ja| ''Nein'' : false: || ''Oui'' : true: |Oui| ''Non'' : false: || ''Yes'' : true: |Yes| ''No'' : false: ||

... y no te olvides de RTFM!

man -P''less +"/0 but [a-z]*"'' perlfunc ... "fcntl". Like "ioctl", it maps a 0 return from the system call into "0 but true" in Perl. This string is true in boolean context and 0 in numeric context. It is also exempt from the normal -w warnings on improper numeric conversions. ...


Otro ejemplo de "0 pero cierto":

El módulo DBI utiliza "0E0" como valor de retorno para consultas ACTUALIZADAS o BORRADAS que no afectaron ningún registro. Se evalúa como verdadero en un contexto booleano (lo que indica que la consulta se ejecutó correctamente) y en 0 en un contexto numérico que indica que la consulta no modificó ningún registro.


Porque está codificado en el núcleo de Perl para tratarlo como un número. Este es un truco para hacer que las convenciones de Perl y las convenciones de ioctl jueguen juntas; desde perldoc -f ioctl :

El valor de retorno de ioctl (y fcntl ) es el siguiente:

if OS returns: then Perl returns: -1 undefined value 0 string "0 but true" anything else that number

Por lo tanto, Perl devuelve verdadero en caso de éxito y falso en caso de error, sin embargo, aún puede determinar fácilmente el valor real devuelto por el sistema operativo:

$retval = ioctl(...) || -1; printf "System returned %d/n", $retval;

La cadena especial "0 but true" está exenta de las quejas -w sobre conversiones numéricas impropias.


También puede ver la cadena "0E0" utilizada en el código Perl , y significa lo mismo, donde 0E0 solo significa 0 escrito en notación exponencial. Sin embargo, dado que Perl solo considera "0", '''' o undef como falso, se evalúa como verdadero en un contexto booleano.


0 significa falso en Perl (y otros idiomas relacionados con C). En su mayor parte, eso es un comportamiento razonable. Otros idiomas (por ejemplo, Lua) tratan a 0 como verdadero y proporcionan otro token (a menudo nulo o falso ) para representar un valor no verdadero.

Un caso en el que Perl no funciona tan bien es cuando desea devolver un número o, si la función falla por algún motivo, un valor falso. Por ejemplo, si escribe una función que lee una línea de un archivo y devuelve el número de caracteres en la línea. Un uso común de la función podría ser algo como:

while($c = characters_in_line($file)){ ... };

Observe que si el número de caracteres en una línea en particular es 0, el bucle while terminará antes del final del archivo. Por lo tanto, la función characters_in_line debería incluir caracteres de caso especial 0 y devolver ''0 pero verdadero'' en su lugar. De esa manera, la función funcionará como se espera en el bucle while, pero también devolverá la respuesta correcta si se usa como un número.

Tenga en cuenta que esto no es una parte integrada del lenguaje. Más bien, aprovecha la capacidad de Perl para interpretar una cadena como un número. Así que a veces se usan otras picaduras en su lugar. DBI usa "0E0" , por ejemplo. Cuando se evalúan en un contexto numérico, devuelven 0 , pero en un contexto booleano, falso .