2010-10-12 12 views
16

Al evaluar una expresión en un contexto escalar (booleano), Perl usa el valor explícito 1 como resultado si la expresión se evalúa como verdadera y la cadena vacía si la expresión se evalúa como falsa. Tengo curiosidad por saber por qué Perl usa la cadena vacía para representar el valor booleano falso y no 0, que parece más intuitivo.¿Por qué Perl usa la cadena vacía para representar el valor falso booleano?

Tenga en cuenta que no me preocupa que Perl trate la cadena vacía como falsa en el contexto escalar (booleano).

EDITAR

¿Cómo el uso de cuerdas que es verdadero ("false" por ejemplo) como una representación de cadena de valores falsos cambiar el significado del código existente? ¿Podríamos decir que el código que cambia la semántica después de dicho cambio es menos robusto/correcto de lo que podría haber sido? Supongo que el contexto de cadena es tan generalizado en Perl que la única opción que conduce a la semántica sana es si el valor booleano preserva su valor después de un disparo circular hacia y desde una cadena ...

+0

Posible duplicado de [¿Por qué! 1 no me da nada en Perl?] (Http://stackoverflow.com/questions/1134962/why-does-1-give-me-nothing-in-perl) – Thilo

Respuesta

30

Los diversos operadores lógicos no devuelven una cadena vacía, devuelven un valor falso o verdadero en los tres tipos escalares simples. Sólo se ve como que devuelve una cadena vacía porque print fuerza un contexto de cadena en sus argumentos:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Devel::Peek; 

my $t = 5 > 4; 
my $f = 5 < 4; 

Dump $t; 
Dump $f; 

Salida:

SV = PVNV(0x100802c20) at 0x100827348 
    REFCNT = 1 
    FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK) 
    IV = 1 
    NV = 1 
    PV = 0x100201e60 "1"\0 
    CUR = 1 
    LEN = 16 
SV = PVNV(0x100802c40) at 0x100827360 
    REFCNT = 1 
    FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK) 
    IV = 0 
    NV = 0 
    PV = 0x100208ca0 ""\0 
    CUR = 0 
    LEN = 16 

Para aquellos que no están familiarizados con los Perl 5 partes internas, un PVNV es un escalar estructura que contiene los tres tipos escalares simples (número entero IV, flotador de precisión doble NV y cadena PV). Los indicadores IOK, NOK y POK significan que los valores enteros, dobles y de cadena están todos sincronizados (para alguna definición de sincronización) por lo que cualquiera de ellos puede usarse (es decir, no es necesario realizar conversiones si lo usa como un entero, doble o cadena).

Supongo que se eligió la cadena vacía para la cadena falsa porque es más pequeña y es más acorde con la idea de una cadena falsa que "0". Ignore mi afirmación de que es más pequeño, tanto "" como "1" tienen el mismo tamaño: dieciséis caracteres. Dice tan bien en el basurero. Perl 5 agrega espacio extra a las cadenas para permitirles crecer rápidamente.

Oh, y te odio. Al investigar esto, he descubierto que he mentido en perlopquick y ahora tendré que encontrar la manera de solucionarlo. Si solo hubieras sido como todas las otras ovejas y hubieras aceptado la rareza superficial de Perl 5 como un hecho, tendría menos trabajo que hacer.

Las respuestas a las preguntas en la sección EDIT:

¿Cómo sería el uso de cuerdas que es verdadero ("falsa", por ejemplo) como una representación de cadena de falsos valores cambian el significado del código existente?

Las únicas cosas especiales acerca de acerca de PL_sv_yes y PL_sv_no (los valores verdaderos y falsos canónicamente devueltos por los operadores de comparación) son que son de sólo lectura y son creados por perl no el programa que se está ejecutando. Si los modifica, no cambia la prueba de veracidad, por lo que un PL_sv_no que se establece en "false" se tratará como verdadero. Incluso se puede hacer esto por sí mismo (el código deja de funcionar en algún punto entre Perl 5.18 y la última Perl) con características no documentadas de perl:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Scalar::Util qw/dualvar/; 

BEGIN { 
     # use the undocumented SvREADONLY function from Internals to 
     # modify a reference to PL_sv_no's readonly flag 
     # note the use of & to make the compiler not use SvREADONLY's 
     # prototype, yet another reason prototypes are bad and shouldn't 
     # be used 
     &Internals::SvREADONLY(\!!0, 0); 

     # set PL_sv_no to a dualvar containing 0 and "false" 
     ${\!!0} = dualvar 0, "false"; 
} 

if (5 < 4) { 
     print "oops\n"; 
} 

salidas

opps 

Esto se debe a las miradas de prueba truthiness en cuerdas primero.

¿Podríamos decir que el código que cambia la semántica después de dicho cambio es menos robusto/correcto de lo que podría haber sido?

Será directamente roto. Incluso si se limita a configurarlo en un int 0 o en una cadena "0" (ambos son falsos), romperá algún código válido.

supongo contexto de cadena es tan penetrante en Perl que la única opción que lleva a la semántica cuerdo es si el valor booleano preservar su valor después de la ida y vuelta hacia y desde una cadena ...

Sí.

+9

Los odio/amo a los dos: esta pregunta me hizo enviar un docpatch a p5p justo ahora: perlguts se refiere erróneamente a 'PL_sv_no' (el escalar" falso "en cuestión) como' PL_sv_false'. :) – hobbs

+2

@Piotr Dobrogost ¡Mira lo que has hecho! ¿Ves lo que viene de hacer preguntas? ¡Estás mejorando las cosas en Perl 5! ¿Cómo puedes vivir contigo mismo? –

+0

Gracias, aplicado, placas. :-) – rafl

2

It's not just"" that's false in Perl. En cuanto a por qué ... es porque Perl es increíble o terrible, según tus preferencias personales :)

+1

Perl is el único idioma que es igualmente legible antes y después del cifrado RSA. – TBH

+2

@TBH No, APL es. Perl es un poco más legible en forma no encriptada. –

+2

@Chas: creo que quisiste decir "en forma cifrada". – DVK

2

Tanto el número 0 como la cadena vacía finalmente se evalúan como falsos en Perl. Creo que esto es una cuestión de diseño del lenguaje. Al escribir su propio código, puede asumir cualquier convención de codificación falsa.

Para obtener más información, consulte "How do I use boolean variables in Perl?".

5

Puede sobrecargar el stringification verdadero, falso y no def, como this:

&Internals::SvREADONLY(\ !!1, 0); # make !!1 writable 
${ \ !!1 } = 'true';     # change the string value of true 
&Internals::SvREADONLY(\ !!1, 1); # make !!1 readonly again 
print 42 == (6*7);     # prints 'true' 

&Internals::SvREADONLY(\ !!0, 0); # make !!0 writable 
${ \ !!0 } = 'false';     # change the string value of false 
&Internals::SvREADONLY(\ !!0, 1); # make !!0 readonly again 
print 42 == (6*6);     # prints 'false' 
+0

Muy buena personalización. No tenía idea de que Perl permitiera tal cosa. –

+3

Muy mal. +1. – rafl

+0

El paquete 'Internals' y las funciones o variables en él no son para el consumo público (de ahí el nombre). Cambiar globalmente el valor de los valores verdadero y falso devueltos por los operadores es desaconsejable en extremo. Evitar el prototipo de 'SvREADONLY' es simplemente la guinda del pastel. Dicho eso, ingenioso. –

1

Aquí es cómo llegué a solucionar el problema:

my $res = ($a eq $b) *1; 

El *1 convierte el booleano que resulta de ($a eq $b) en un escalar

Cuestiones relacionadas