Почему Perl использует пустую строку для представления логического значения false? - PullRequest
18 голосов
/ 12 октября 2010

При оценке выражения в скалярном (логическом) контексте Perl использует явное значение 1 в качестве результата, если выражение оценивается как true, и пустую строку, если выражение оценивается как false. Мне любопытно, почему Perl использует пустую строку для представления логического ложного значения, а не 0, что кажется более интуитивным.

Обратите внимание, что меня не касается Perl, который рассматривает пустую строку как false в скалярном (логическом) контексте.

EDIT

Как использование строки, которая является истинной (например, "false"), в качестве строкового представления ложных значений изменило бы значение существующего кода? Можем ли мы сказать, что код, который меняет семантику после такого изменения, менее надежен / корректен, чем мог бы быть? Я предполагаю, что строковый контекст настолько распространен в Perl, что единственная опция, ведущая к разумной семантике, - это если логическое значение сохраняет свое значение после округления до строки и из строки ...

Ответы [ 5 ]

32 голосов
/ 12 октября 2010

Различные логические операторы не возвращают пустую строку, они возвращают значение false или true во всех трех простых скалярных типах. Похоже, он возвращает пустую строку, потому что print вызывает строковый контекст в своих аргументах:

#!/usr/bin/perl

use strict;
use warnings;

use Devel::Peek;

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

Dump $t;
Dump $f;

Выход:

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

Для тех, кто не знаком с внутренними компонентами Perl 5, PVNV - это скалярная структура, которая содержит все три простых скалярных типа (целое число IV, число с плавающей запятой двойной точности NV и строка PV). Флаги IOK, NOK и POK означают, что целочисленные, двойные и строковые значения синхронизированы (для некоторого определения в синхронизации), поэтому может использоваться любое из них (т. Е. Преобразование не требуется. иметь место, если вы используете его как целое число, двойное число или строку).

Я предполагаю, что пустая строка была выбрана для ложной строки, потому что она меньше и больше соответствует идее ложной строки, чем "0". Не обращайте внимания на мое утверждение о том, что оно меньше, "" и "1" имеют одинаковый размер: шестнадцать символов. Так сказано прямо на свалке. Perl 5 добавляет дополнительное пространство к строкам, чтобы они могли быстро расти.

Ох, и я тебя ненавижу. Исследуя это, я обнаружил, что я лгал в perlopquick и теперь должен найти способ исправить это. Если бы вы были такими же, как все остальные овцы, и просто приняли странность поверхности Perl 5 как факт, у меня было бы меньше работы.

Ответы на вопросы в разделе РЕДАКТИРОВАНИЯ:

Как использование строки true (например, false) в качестве строкового представления ложных значений изменит смысл существующего кода?

Единственное, что особенного в PL_sv_yes и PL_sv_no (канонически истинных и ложных значениях, возвращаемых операторами сравнения), заключается в том, что они доступны только для чтения и создаются perl, а не программой, которая выполняется. Если вы измените их, это не изменит тест на достоверность, поэтому PL_sv_no, установленное на "false", будет считаться истиной. Вы даже можете сделать это самостоятельно (этот код перестает работать в какой-то момент между Perl 5.18 и последней версией Perl), используя недокументированные функции 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";
}

выходы

opps

Это потому, что тест на правдивость сначала проверяет строки.

Можно ли сказать, что код, который меняет семантику после такого изменения, менее надежен / корректен, чем мог бы быть?

Это будет прямо сломано. Даже если вы ограничитесь установкой значения int 0 или строки «0» (оба значения false), это приведет к нарушению допустимого кода.

Я полагаю, что строковый контекст настолько распространен в Perl, что единственная опция, ведущая к разумной семантике, - это если логическое значение сохраняет свое значение после округления до строки и из строки ...

Да.

5 голосов
/ 12 октября 2010

Вы можете перегружать строковые значения true, false и undef, например 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'
2 голосов
/ 12 октября 2010

И число 0, и пустая строка в конечном итоге оцениваются как ложные в Perl.Я думаю, что это вопрос языкового дизайна.При написании собственного кода вы, конечно, можете принять любое ложное соглашение о кодировке.

Для получения более подробной информации, посмотрите " Как использовать булевы переменные в Perl? ".

2 голосов
/ 12 октября 2010

Это не просто "", это неверно в Perl . Что касается того, почему ... это либо потому, что Perl потрясающий или ужасный - в зависимости от ваших личных предпочтений:)

1 голос
/ 03 декабря 2014

Вот как я обошёл проблему:

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

*1 преобразует логическое значение, полученное в результате ($a eq $b), в скаляр.

...