Высказывания и истинность: что на самом деле проверяет ваш if
Высказывание — это утверждение, которое либо истинно, либо ложно: третьего не дано. «x > 3» становится высказыванием, лишь когда x получает значение, а каждое условие if — высказывание в момент выполнения. Баги truthiness начинаются там, где кончается строгая истинность.
Подумайте про обычные предложения. «Идёт дождь» — это то, что можно просто назвать истинным или ложным, выглянув в окно. «Закрой окно!» — нет: это приказ, а не утверждение, и называть его «ложным» бессмысленно. «Опаздывает ли автобус?» — вопрос, который просит ответ «истина или ложь», а не даёт его. Вся логика построена на предложениях первого вида — тех, что обязаны быть либо истинными, либо ложными, — и на них же построено каждое решение вашего кода. Платёжный стартап однажды выкатил правку в одну строку: читать флаг администратора из конфига вместо базы. В файле значилось isAdmin: "false" — строка. Проверка if (user.isAdmin) стала проходить у каждого пользователя: в JavaScript непустая строка truthy. Шесть часов любой видел панель возвратов. Баг был не опечаткой — это была подмена высказываний.
После этого урока ты можешь сказать, что такое высказывание, объяснить, почему команды и вопросы высказываниями не являются, описать, что свободная переменная делает с предложением, подставить значение, чтобы замкнуть открытое предложение, и определить, какое именно высказывание вычисляет условие if.
Высказывание — предложение ровно с одним значением истинности. Высказывание (proposition) — это повествовательное предложение, которое либо истинно, либо ложно: ровно одно из двух, никогда оба, никогда ни одно. «7 — чётное число» — высказывание: оно ложно, и это нормально — ложное утверждение остаётся полноценным высказыванием. «Закрой дверь!» — не высказывание: команду можно выполнить или проигнорировать, но нельзя назвать истинной или ложной.
Вопросы и суждения вкуса тоже исключены. «Сервер работает?» запрашивает значение истинности, а не утверждает его. «Эта пицца восхитительна» — дело вкуса, и классическая логика его не принимает. Два значения истинности записывают И и Л (или true и false). Логику не волнует, о чём высказывание — она следит только за этим одним битом.
Предложение со свободной переменной — не высказывание, а открытое предложение. Взгляните на «x > 3». Истина или ложь? Сказать нельзя — всё зависит от x. Предложение со свободной переменной (заполнителем без значения) называется открытым предложением (предикатом). Подставьте значение — и оно замкнётся: связать x = 7 → «7 > 3», истинное высказывание; связать x = 1 → «1 > 3», ложное.
Условие if — открытое предложение, которое рантайм замыкает. Каждый if, while и тернарник — это рантайм, строящий и вычисляющий высказывание. Вы пишете открытое предложение; выполнение связывает переменные; результат обязан схлопнуться в один бит: войти в ветку или нет. В языках с приведением типов, как JavaScript, любое значение втискивается в истину или ложь по правилам truthiness — поэтому строка "false" ведёт if так же уверенно, как true.
Классифицируйте каждое предложение: высказывание, открытое предложение или ни то ни другое?
- «HTTP-запрос вернул статус 200.»
- «Закрой соединение!»
- «count > limit» (где
countиlimit— несвязанные переменные) - «count > limit» (где
count = 50000иlimit = 100)
Предложение 1 — высказывание: оно утверждает факт, который либо истинен, либо ложен.
Предложение 2 — ни то ни другое: команда; её можно выполнить или проигнорировать, значения истинности нет.
Предложение 3 — открытое предложение: обе переменные свободны, значения истинности пока нет.
Предложение 4 — высказывание: связав count = 50000 и limit = 100, замыкаем предложение. «50000 > 100» — истинно.
Практический вывод: каждый написанный вами if (count > limit) — это предложение 3 в момент написания кода. Рантайм превращает его в предложение 4 — а если limit так и не был присвоен, JavaScript молча вычисляет 50000 > undefined, что через NaN даёт false. Настоящее высказывание, только не то, что вы имели в виду.
▸Почему это работает
Почему логика настаивает на ровно одном значении истинности? Потому что всё дальнейшее — таблицы истинности, доказательства, эквивалентности из следующих уроков — работает, отслеживая, как истинность перетекает из малых утверждений в большие. Если бы предложение могло быть одновременно истинным и ложным, можно было бы «доказать» что угодно. Булева колонка с тремя состояниями (true, false, NULL) — знаменитый источник багов по той же причине: третье состояние ломает все допущения, написанные для двух.
Является ли «7 — простое число» высказыванием? Напишите да или нет.
Является ли «Выключи свет!» высказыванием? Напишите да или нет.
Является ли «x + 1 > 5» при несвязанном x высказыванием? Напишите да или нет.
Свяжем x = 10 в «x + 1 > 5». Истина или ложь?
В JavaScript выполняется ли ветка if('false')? Напишите да или нет.
Что из перечисленного является высказыванием?
Высказывание — это повествовательное предложение ровно с одним значением истинности: истина или ложь, никогда оба, никогда ни одно. Команды, вопросы и дела вкуса тест не проходят; ложные утверждения проходят, потому что входное условие — нести значение истинности, а не быть истинным. Предложение со свободной переменной — открытое предложение: само по себе не высказывание, а шаблон, который становится им после связывания каждой переменной значением. Каждое условие if — открытое предложение, написанное на этапе кодирования, которое рантайм замыкает при выполнении. Опасная зона — зазор между высказыванием, которое вы имели в виду, и тем, которое строит машина: неприсвоенная переменная всё равно связывается (с undefined, и 50000 > undefined через NaN даёт false), а языки с приведением типов вычисляют truthiness, и непустая строка «false» ведёт if так же уверенно, как true. Дисциплина: превращайте недоверенный строковый ввод в настоящие були на границе, сравнивайте строго, и всегда умейте сказать, какое именно высказывание вычисляет ваше условие.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.