¿Por qué Perl usa la cadena vacía para representar el valor falso booleano?
boolean-expression (5)
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 un valor falso booleano y no 0
que parece más intuitivo.
Tenga en cuenta que no me preocupa que Perl trate la cadena vacía como falsa en un contexto escalar (booleano).
EDITAR
¿Cómo utilizar una cadena que es verdadera ( "false"
por ejemplo) como una representación de cadenas de valores falsos cambiaría el significado del código existente? ¿Podríamos decir que el código que cambia la semántica después de tal cambio es menos sólido / correcto de lo que podría haber sido? Supongo que el contexto de la cadena es tan generalizado en Perl que la única opción que conduce a una semántica sana es si el valor booleano conserva su valor después del disparo de ida y vuelta a una cadena ...
Así es como resolví el problema:
my $res = ($a eq $b) *1;
El *1
convierte el booleano resultante de ($a eq $b)
en un escalar.
Los diversos operadores lógicos no devuelven una cadena vacía, sino que devuelven un valor falso o verdadero en los tres tipos de escalar simple. Simplemente parece que devuelve una cadena vacía porque la 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 las PVNV
internas de Perl 5, un PVNV
es una estructura escalar que contiene los tres tipos de PVNV
simples (entero IV
, NV
flotación de doble precisión y PV
cadena). Las banderas IOK
, NOK
y POK
significan que los valores de entero, doble y cadena están sincronizados (para alguna definición de sincronización), por lo que se puede usar cualquiera de ellos (es decir, no es necesario realizar conversiones si lo usa) como un entero, doble o cadena).
Asumo que la cadena vacía se eligió para la cadena falsa porque es más pequeña y está más en consonancia 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. Lo dice justo en el basurero. Perl 5 agrega espacio adicional a las cadenas para permitirles crecer rápidamente.
Oh, y te odio. Al investigar esto, he encontrado que he mentido en perlopquick
y ahora tendré que encontrar una 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.
Respuestas a las preguntas en la sección EDITAR:
¿Cómo utilizar una cadena que es verdadera ("falsa" por ejemplo) como una representación de cadenas de valores falsos cambiaría el significado del código existente?
Las únicas cosas especiales acerca de PL_sv_yes y PL_sv_no (los valores canónicamente verdaderos y falsos devueltos por los operadores de comparación) son que son de solo lectura y son creados por perl
no por el programa que se está ejecutando. Si los cambia, no cambia la prueba de veracidad, por lo que un PL_sv_no que se establece en "false"
se tratará como verdadero. Incluso puede hacerlo usted mismo (este código deja de funcionar en algún punto entre Perl 5.18 y el último Perl) usando 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 que la prueba de la verdad mira las cadenas primero.
¿Podríamos decir que el código que cambia la semántica después de tal cambio es menos sólido / correcto de lo que podría haber sido?
Será recto hasta roto. Incluso si te limitas a configurarlo en un int 0 o una cadena "0" (ambos de los cuales son falsos), romperá algún código válido.
Supongo que el contexto de la cadena es tan generalizado en Perl que la única opción que conduce a una semántica sana es si el valor booleano conserva su valor después del disparo de ida y vuelta a una cadena ...
Sí.
Puedes sobrecargar la cadena de caracteres verdadero, falso y undef, así:
&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''
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, por supuesto, puede asumir cualquiera que sea una convención de codificación falsa.
Para más detalles, consulte " ¿Cómo uso las variables booleanas en Perl? ".
No es solo ""
eso es falso en Perl . En cuanto a por qué ... es porque Perl es increíble o terrible, dependiendo de tus preferencias personales :)