2010-10-12 6 views
16

Quando si valuta un'espressione in un contesto scalare (booleano), Perl utilizza il valore esplicito 1 come risultato se l'espressione restituisce true e la stringa vuota se l'espressione restituisce false. Sono curioso di sapere perché Perl utilizza la stringa vuota per rappresentare il valore falso booleano e non 0 che sembra più intuitivo.Perché Perl utilizza la stringa vuota per rappresentare il valore falso booleano?

Nota che non mi interessa il fatto che Perl tratti la stringa vuota come un falso nel contesto scalare (booleano).

EDIT

Come sarebbe utilizzando stringa che è vero ("false" per esempio) come una rappresentazione di stringa di falsi valori cambiare il significato di codice esistente? Potremmo dire che il codice che cambia semantica dopo un tale cambiamento è meno robusto/corretto di quanto avrebbe potuto essere? Immagino che il contesto delle stringhe sia così pervasivo in Perl che l'unica opzione che porta alla semantica ragionevole è se il valore booleano conserva il suo valore dopo lo sgancio da e verso una stringa ...

+0

Possibile duplicato di [Perché non mi dà nulla in Perl?] (Http://stackoverflow.com/questions/1134962/why-does-1-give-me-nothing-in-perl) – Thilo

risposta

30

I vari operatori logici non restituiscono una stringa vuota, restituiscono un valore falso o vero in tutti e tre i semplici tipi scalari. Sembra proprio come restituisce una stringa vuota perché print costringe un contesto stringa sui suoi argomenti:

#!/usr/bin/perl 

use strict; 
use warnings; 

use Devel::Peek; 

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

Dump $t; 
Dump $f; 

uscita:

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 

Per chi non ha familiarità con i Perl 5 interni, un PVNV è uno scalare struttura che contiene tutti e tre i tipi scalari semplici (numero intero IV, galleggiante a precisione doppia NV e stringa PV). Le flag IOK, NOK e POK significano che i valori interi, double e string sono tutti sincronizzati (per alcune definizioni di sync) in modo che uno di essi possa essere utilizzato (ovvero non è necessario effettuare conversioni se lo si utilizza come un numero intero, doppio o stringa).

Presumo che la stringa vuota sia stata scelta per la stringa falsa perché è più piccola e è più in linea con l'idea di una stringa falsa di "0". Ignora la mia affermazione che è più piccolo, sia "" che "1" hanno la stessa dimensione: sedici caratteri. Dice così bene nella discarica. Perl 5 aggiunge ulteriore spazio alle stringhe per consentire loro di crescere rapidamente.

Oh, e io ti odio. Nella ricerca di questo ho scoperto che ho mentito in perlopquick e ora dovrò trovare un modo per risolverlo. Se solo fossi stato come tutte le altre pecore e avessi accettato la stranezza della superficie di Perl 5 come un fatto, avrei meno lavoro da fare.

Risposte alle domande nella sezione EDIT:

Come sarebbe utilizzando stringa che è vero ("false" per esempio) come una rappresentazione di stringa di falsi valori cambiano il significato del codice esistente?

Le uniche cose speciali circa circa PL_sv_yes e PL_sv_no (i valori canonicamente vero e falso restituiti da operatori di confronto) sono che essi sono di sola lettura e sono creati da perl non il programma in esecuzione. Se li si modifica, non cambia il test di verità, quindi un PL_sv_no impostato su "false" verrà considerato come true. Si può anche fare da soli (il codice smette di funzionare ad un certo punto tra Perl 5.18 e l'ultima Perl) utilizzando le funzionalità non documentate di 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"; 
} 

uscite

opps 

Questo perché gli sguardi di prova truthiness prima agli archi.

Possiamo dire che il codice che cambia semantica dopo un tale cambiamento è meno robusto/corretto di quanto avrebbe potuto essere?

Sarà dritto rotto. Anche se ti limiti a impostarlo su un 0 o una stringa "0" (entrambi sono falsi), si romperà del codice valido.

immagino contesto corda è così pervasiva in Perl che l'unica opzione che porta alla semantica sane è se il valore booleano preservare il suo valore dopo round intervento da e verso una stringa ...

Sì.

+9

Odio/amo entrambi: questa domanda mi ha indotto a inviare un docpatch a p5p proprio ora: perlguts si riferisce erroneamente a 'PL_sv_no' (lo" scalare "falso in questione) come' PL_sv_false'. :) – hobbs

+2

@Piotr Dobrogost Guarda cosa hai fatto! Vedi cosa viene dal fare domande? Stai migliorando le cose in Perl 5! Come puoi vivere con te stesso? –

+0

Grazie, applicato, hobbs. :-) – rafl

2

It's not just"" that's false in Perl. Per quanto riguarda il perché ... è perché Perl è fantastico o terribile, a seconda delle preferenze personali :)

+1

Perl è l'unico linguaggio che è ugualmente leggibile prima e dopo la crittografia RSA. – TBH

+2

@TBH No, APL è. Perl è leggermente più leggibile in forma non criptata. –

+2

@Chas - Penso che intendessi dire "in forma crittografata". – DVK

2

Sia il numero 0 che la stringa vuota vengono valutati come falsi in Perl. Penso che sia una questione di design del linguaggio. Quando scrivi il tuo codice, puoi ovviamente assumere qualsiasi convenzione di codifica falsa.

Per ulteriori dettagli, consultare "How do I use boolean variables in Perl?".

5

È possibile sovraccaricare il in stringa di vero, falso e undef, come 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

Personalizzazione molto bella. Non avevo idea che Perl consentisse una cosa del genere. –

+3

Quindi molto sbagliato. +1. – rafl

+0

Il pacchetto 'Internals' e le sue funzioni o variabili non sono per il consumo pubblico (da cui il nome). La modifica globale del valore dei valori true e false restituiti dagli operatori è sconsigliabile in casi estremi. L'elusione del prototipo di 'SvREADONLY' è solo la ciliegina sulla torta. Detto questo, elegante. –

1

Ecco come ho ottenuto il problema:

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

Il *1 converte il booleano risultante da ($a eq $b) in uno scalare.