[Перевод] Смыть

Привет, Хабр! Представляю вашему вниманию перевод статьи «To Wash It All Away» автора James Mickens.



Когда я учился в аспирантуре в Анн-Арбор, у меня был друг, глубоко увлеченный движением защитников окружающей среды. Он покупал еду у местных фермеров, ездил на велосипеде вместо машины, желая уменьшить выбросы, и держал жуткое компостное ведро, которое, вероятно, будет источником следующей пандемии гриппа. Однажды он сказал мне, что собирается неделю пожить на ферме. Я спросил зачем, и он ответил, что хочет «побыть ближе к земле» — фраза, которую вы можете произнести с серьёзным лицом, только комментируя документальный фильм о древних южноамериканских племенах. Я сказал моему другу, что земля не хочет побыть ближе к нему и что если бы он действительно присмотрелся к земле, то увидел бы не молочные реки и кисельные берега, а голод, стервятников, непосильный труд с использованием тачек и в целом неприемлемые количества насекомых. Он разразился продолжительной лекцией об экологической ответственности, которую я тут же выбросил из головы, потому что понял, что мой наивный друг даст дуба на этой ферме, и посоветовал ему без колебаний возвращаться, если вдруг ему там будет недостаточно хорошо. Он улыбнулся мне так, как улыбаются люди в фильмах ужасов за минуту до встречи с топором, и отчалил. Ровно 37 часов спустя он позвонил. Я поинтересовался, как идут дела, на что он ответил протяжным, леденящим душу звуком, подобным пению сирен в брачный период. Я попросил его описать свой первый день, и он ответил, что всё его бытие вращалось вокруг блеющих вещей: блеющих коз, хотевших есть, блеющих ворон, хотевших стырить еду у блеющих коз и блеющих механизмов, состоящих из вращающихся стальных лезвий и не имеющих никакого разумного применения, не считая обеспечения вам членства в клубе «Протез месяца».
Я спросил своего друга, когда же он собирается домой, на что он ответил, что звонит с вокзала в Анн-Арбор; он уже здесь. А затем он опять выдал тот вой сирен, тот жуткий, протяжный звук, и я понял — ПОХОЖЕ, ЭТО ПЕРВЫЙ СИМПТОМ КОМПОСТОВЕДЕРНОГО ГРИППА.

ИТ-специалисты часто видят в веб-страницах то, что мой друг видел в фермах. Люди думают, что веб-браузеры — это такие элегантные вычислительные платформы, и что веб-страницы — это такие легкие, пушистые штуковины, которые вы можете редактировать в блокноте, перекидываясь ироничными комментариями с друзьями в кофешопе. Нет ничего более далекого от истины. Современная веб-страница — это катастрофа. Она подобна сцене с одной из тех апокалиптических средневековых картин, изображающих последствия пришествия Галактуса: люди катятся кубарем в огненную бездну, сокрушаются различными сокрушающими штуками и свисают с оборудования для детских площадок, которое не прошло бы сертификацию безопасности. Это именно то, что вы увидите, взглянув на HTML, CSS и JavaScript в современной веб-странице. Нет, разумеется, ни один человек не в состоянии действительно «взглянуть» на это содержимое, потому что типичная веб-страница в наши дни подобна V'Ger из первого Стар Трека — технология, которую мы когда-то понимали, а теперь не можем даже осознать, сокрушающий левиафан кода и разметки, написанных людьми настолько ненадежными, что они тут даже не третья сторона, они пятая сторона, вообще НЕ ЗВАННАЯ на эту вечеринку, но явившаяся всё равно, потому что хиппи были правы и свободная любовь или пофиг. Я уверен, что веб-браузер — один из тех «нечестивых притонов», о которых постоянно твердят по Fox News; Я бы проверил это лично поиском в сети, но поиск в сети потребовал бы от меня использования браузера, А ЭТО ИМЕННО ТО, ЧТО ВЕЗДЕСУЩИЕ ЛИБЕРАЛЬНЫЕ ЭЛИТЫ ОТ МЕНЯ ХОТЯТ.

Описание того, почему Веб ужасен, подобно описанию того, почему ужасно тонуть в океане из рыб фугу, беременных маленькими Фредди Крюгерами — каждая деталь кошмарна сама по себе, но совокупная сумма восхитительно складывается в вечнозелёный цветок ненависти. Например, Консорциум Всемирной паутины (W3C) предоставляет «официальные» спецификации для многих веб-технологий на стороне клиента. К сожалению, эти спецификации являются обязательными к исполнению производителями браузеров примерно в той же степени, в которой вы, в принципе, можете попросить ядозуба встретить вас в аэропорту[1], но у ядозуба, пожалуй, найдутся более интересные занятия. Каждый документ W3C наполнен омерзительными предложениями, в основном состоящими из гиперссылок на гиперссылки. Например, если вы производитель браузера и хотите добавить поддержку HTML селекторов, вы должны помнить, что на третьем этапе разбора строки селектора «Если результат недействителен ([SELECT], раздел 12), следует бросить исключение SYNTAX_ERR ([DOM-LEVEL-3-CORE], раздел 1.4) и прервать этот алгоритм». Подобный романтический этюд в канцелярских тонах, несомненно, будет по нраву людям, тоскующим по тупости списка ингредиентов Доширака, помноженного на многослойную бюрократию Советского Союза. Действительно, можно представить себе мир, в котором производители браузеров нанимают легионы толкователей Талмуда, дабы понять, почему SYNTAX_ERR именно оранжевый, а не лиловый, и как именно эта оранжевость относится к оскобоченной лиловости ([DOM-LEVEL-3-CORE]). А еще можно представить себе мир, где производители браузеров таким не занимаются, реализуя вместо этого 53% каждой спецификации, а затем надеясь, что ни одна веб-страница не попытается использовать HTML селекторы, затем интерфейс геолокации, а затем тег <canvas>, потому что это комбо освободит Антихриста и/или отобразит веб-страницу, подобную одной из тех работ Пикассо, которые вы якобы понимаете, но которые все втихаря хотят выбросить в океан, потому что никому нет радости созерцать изображение голубого человека из равнобедренных треугольников с растущей изо лба гитарой без всякой на то причины.

[1] «Ядозубы встретят тебя в аэропорту» — название реальной детской книжки, оказавшей огромное влияние на мой эмоциональный рост. Её неустрашимый реализм вдохновил меня на написание моей собственной серии негативно воспринятых детских книг, таких как «Пауки съели твою сестру, о которой мы никода не говорим», «Капиталистическая реклама заставляет тебя ненавидеть своё тело и покупать вещи, созданные рабским трудом» и «Я могу солгать и сказать, что мне интересна твоя коллекция комиксов, или сказать правду и пояснить, почему с тобой не хотят встречаться».

Учитывая невыносимое разбухание веб-стандартов и клоунски невнятную семантику этих стандартов, производителям браузеров стоит просто плюнуть и посоветовать обществу перестать хотеть странного. Однако, это мнение непопулярно, потому что никто не станет смотреть ваше выступление на TED, если ваше чувство оптимизма базируется на реальности. Я то и дело пытаюсь объяснить друзьям, почему они должны отказаться от веб-страниц и обмениваться информацией с помощью солнечного света, отраженного от системы зеркал, ну или энергичного махания цветными флажками. Мои друзья неизбежно отвечают бессмысленным набором слов типа «люди изобрели летательные аппараты, поэтому мы, несомненно, в состоянии сделать хороший браузер!». К сожалению, критерий успешности летательного аппарата прост («Я ЭТО Я НО Я ПТИЦА»), в то время как критерий успешности веб-браузера включает в себя каскадные таблицы стилей — технологию, одним своим существованием обрекающую любой проект на былинную неудачу. Для непосвященных, каскадные таблицы стилей — это такая тайнопись, разработанная масонами для сокрытия визуальной природы реальности и побуждения людей к рисованию картин псевдографикой. CSS-файлы якобы позволяют вам отделить определение вашего содержимого от определения того, как это содержимое выглядит — используя CSS, вы можете задать размещение для ваших HTML тегов, а также шрифтов и цветовых схем, используемых этими тегами. К сожалению, CSS и HTML сочетаются так же, как инструкция по сборке вашей кровати из IKEA и набор злобных деревянных палок, якобы таящих в себе структуру кровати. CSS — это не столько описание того, как ваша веб-страница будет в конце концов выглядеть, сколько поверхностный, высокоуровневый обзор того, что может случиться с вашей страницей в зависимости от погоды, ситуации на фондовом рынке и когда вы последний раз звонили маме. Подобно наивному гейм-мастеру, не испорченному печалями взрослой жизни, вы создаёте абстрактные CSS классы для тегов <div> и тегов <span>, распределяя их сильные и слабые стороны, и определяя роли, которые они будут играть во всеобъемлющем и возвышенном повествовании вашего HTML. Всё строго на своих местах; вы загружаете страницу в браузер и готовитесь к славной победе. Однако, вскоре вы обнаруживаете, что ваш тег <эльф> имеет лишний вес. ЭЛЬФ НЕ МОЖЕТ ИМЕТЬ ЛИШНИЙ ВЕС. Даже хуже, у вашего тега <варвар> нет здоровенного молота или топора. Без здоровенного молота или топора ВАШ ВАРВАР ПРОСТО НЕГРАМОТНЫЙ КАЧОК. А потом вы смотрите на ваш тег <маг> и видите, что это не белый старикан с развевающейся бородой, а молодой негр из Бруклина. ПО МНОЖЕСТВУ КОМПЛЕКСНЫХ ПРИЧИН, БЕРУЩИХ СВОЁ НАЧАЛО В ЕВРОПЕЙСКИХ КОЛОНИАЛЬНЫХ ПОВЕСТВОВАНИЯХ, ВАШ МАГ ОБЯЗАН БЫТЬ БЕЛЫМ СТАРИКАНОМ С РАЗВЕВАЮЩЕЙСЯ БОРОДОЙ, А НЕ НЕГРОМ В ХИПСТЕРСКИХ ТУФЛЯХ И С РОСКОШНОЙ КОЛЛЕКЦИЕЙ ПЛАСТИНОК. Таковы беды, что посеет вам CSS. Или пожнёшь ты. Честно говоря, я не знаю, какой глагол и в какой форме тут более уместен, но, уверен, что вы меня поняли. На рисунке 1 конкретный пример CSS-ного посевательства. Или CSS-овского посевательства. МОИ НЕКАСКАДНЫЕ РУКОВОДСТВА ПО СТИЛЯМ СРАЖАЮТСЯ ЗА МОЮ ДУШУ.



Рисунок 1: Как-то раз я пытался соорудить кроссбраузерную отладочную инфраструктуру. У меня была клиентская JavaScript библиотека, способная пройтись по куче JavaScript'а и отобразить забавные штуки о состоянии страницы. Мои друзья-гуманитарии уверили меня, что вывод в консоль — удел неандертальцев, так что я сделал интерфейс на HTML для отображения диагностической информации. Первая версия интерфейса использовала политики компоновки браузера по умолчанию. Совсем как Икар, я мечтал о большем, поэтому я решил сделать Вычурную КомпоновкуTM. Я написал CSS с указаниями, должны ли мои теги быть расположены статически, динамически или же относительно знака зодиака. Вот что я узнал: никогда не указывайте, должны ли ваши теги быть расположены статически, динамически или же относительно знака зодиака. Как только один-единственный тег сбросит оковы автоматического процесса компоновки, браузер немедленно поедет крышей и сложит случайные HTML-теги кучкой вдоль оси Z, оси, видимо, являющейся приемлемым вариантом, даже если ваш монитор может отображать только два измерения. В конце концов я нашел рабочий файл CSS в бутылке, выброшенной на берег, и твикал его до тех пор, пока он не заработал в моем интерфейсе. Потом я пошел домой, роняя скупые мужские слёзы, наполненные сюрикенами и превращающиеся во львов, едва касаясь земли.

Если вы веб-разработчик, CSS — лишь одна из ваших забот. Совокупный стек веб-технологий настолько хрупок, что разработчики просто смирились с тем, что различные части веб-страницы будут отваливаться в произвольные моменты времени. Видимо, это норма, потому что электронную коммерцию никто не воспринимает всерьез, и, если вы действительно жаждете безопасных банковских операций, вы не прочь посетить банк лично, как в 19 веке, вместо использования веб-портала банка, постоянно (но втихаря) извергающего ошибки исполнения в консольный лог (консольный лог, который браузер по умолчанию вам не показывает, потому что если бы вы знали о нём и внемлили его горестным былинам, вы бы бросили информатику и переключились на изготовление деревянных башмаков).
На рисунке 2 представлен оригинальный пример такого консольного лога; лог был сгенерирован реальной веб-страницей на одном популярном сайте.


Рисунок 2: Они сказали, что я могу быть кем угодно, и теперь я лог ошибок веб-браузера. У меня пятнадцать кошек, где все вечеринки?

  • Первая запись лога говорит нам, что браузер исполнил загруженный файл как JavaScript, несмотря на то, что MIME тип файла — text/html. Мой вам совет: если вы не в курсе, что перед вами, НЕ ИСПОЛНЯЙТЕ ЭТО В НАДЕЖДЕ ПОЛУЧИТЬ БОЛЬШЕ ИНФОРМАЦИИ. Это все равно что подметить, что ваш сосед — жуткий оборванец с бегающими глазами, а затем начать ложиться спать у него на пороге, используя тряпку с хлороформом в качестве подушки, исключительно чтобы убедиться, что он не станет привязывать вас к батарее и заставлять раскрашивать крошечные фигурки. Я скажу вам, чем это кончится: ВЫ РАСКРАШИВАЕТЕ КРОШЕЧНЫЕ ФИГУРКИ.
  • Вторая и третья ошибки говорят нам, что в скрипте страницы используется имя переменной, считающееся устаревшим в строгом режиме, но приемлимое в вычурном режиме. Даже не знаю, с какого конца начинать этот прелестный рогалик, начинённый ужасом? Внемлите же: когда мужчина и женщина влюбляются, они хотят продемонстрировать друг другу свои чувства. А потому они заставляют браузеры поддерживать различные режимы исполнения. «Стандартный режим» ссылается на ненадежные интерфейсы браузера, описанные в последних спецификациях HTML и CSS. «Вычурный режим» ссылается на ненадежные интерфейсы браузера, существовавшие в браузерах во времена администрации Эйзенхауэра. Вычурный режим был создан из-за того, что множество веб-страниц также было создано во времена администрации Эйзенхауэра и компьютерная индустрия хотела сохранить сетевые разглагольствования о том, как «рок-н-ролл» развращает нашу молодежь. Вычурный режим выжил потому, что веб-разработчики узнали о вычурном режиме и использовали его в качестве предлога, чтобы не учиться новым трюкам. Но потом нашлись и веб-разработчики, хотевшие учиться новым трюкам, поэтому был придуман стандартный режим, позволяющий этим разработчикам ходить по старым граблям на новый лад. А ещё есть третий режим браузера под названием «почти стандартный режим»; этот режим аналогичен стандартному, за исключением того, что он выводит изображения внутри ячеек таблицы, используя алгоритм вычурного режима. По причинам, съеденным антилопой гну, «почти стандартный режим» также называют «строгим» режимом, хотя он и менее строг, чем стандартный режим. По причинам, чудовищным настолько, что антилопа гну отказалась их есть, не существует полностью надежного способа заставить все браузеры загрузить страницу в одном и том же режиме совместимости. Таким образом, даже если ваша страница прочтет все рекомендуемые заклинания, браузер по-прежнему может делать то, что он хочет и так, как он хочет. И именно отсюда берутся дети.
  • Четвертая и седьмая ошибки представляют собой необработанные исключения JavaScript. В адекватной вселенной одно-единственное необработанное исключение завершит программу, а если бы программа продолжила выполняться после возникновения такого исключения, мы бы поняли, что наступил Рагнарёк и Один не в духе. В мире браузеров же игнорирование необработанных исключений называются «среда, а также все дни, которые не 'среда'». Циклу событий JavaScript мало дела до традиционных понятий о надежности программного обеспечения, а потому, если обработчик события бросит исключение, цикл событий натурально сделает вид, что ничего не произошло, и пойдет дальше. Этот цирк с конями продолжается, даже если, как в случае с седьмой ошибкой, веб-страница пытается вызвать init() у объекта, не имеющего метода init(). Вы должны испытывать дискомфорт от осознания того, что у веб-страницы раздвоение мнения о наличии процедур инициализации, но странице по прежнему дозволено вытворять всякое. Такое резкое несоответствие ожиданий действительности было бы неприемлемо в любом другом контексте. Вы бы огорчились, если бы легли в больничку вырезать аппендицит и во время операции хирург сказала «Я НЕ ОЖИДАЛА, ЧТО У ВАШЕЙ ПЕЧЕНИ БУДУТ ЖАБРЫ», а затем продолжила действовать по своему изначальному хирургическому плану, несмотря на то, что вы, похоже, русалка. То, что вы русалка, должно иметь неигнорируемые последствия в материальной вселенной. Аналогично, если веб-страница думает, что объект должен быть инициализирован, но у объекта нет метода инициализации, браузер не должен ржать и продолжать, полагая, что остальной части страницы безразлично, состоят ли её объекты из белиберды.

Интерпретация остальных ошибок предоставляется читателю в качестве упражнения. Обратите внимание, что для понимания восьмой ошибки нужны кофейная гуща, глаз тритона и хрустальный шар.

На этом месте должно стать интуитивно понятно, что разные браузеры могут или не могут генерировать один и тот же лог ошибок для одной и той же страницы. В общем случае, если веб-страница содержит более трёх бит энтропии, разные браузеры будут генерировать экстравагантно уникальные сочетания намерений веб-разработчика и шизофреничной звериной палитры, используемой браузерами для передачи картины мира. Таким образом, выбор «лучшего браузера» подобен игре в одно из тех жутких упражнений на укрепление доверия, где вы решаете, какие три из ваших пяти чувств вы предпочли бы потерять, а потом ваши коллеги ругают вас за компромиссы, на которые им пришлось пойти, несмотря на то, что не существует частичного упорядочивания, способного сопоставить несчастные случаи при дайвинге, в ходе которых вы теряете ваши глаза и уши, с несчастными случаями на производстве, в ходе которых вы теряете свои нос и язык. Все варианты плохи; это мир топтания на месте. Действительно, попытки выбрать лучший браузер подобны попыткам решить, кто из ваших никчемных детей должен унаследовать семейный бизнес. Маленький Оливер отвергает общепринятые понятия о том, что должен делать цикл обработки событий, поэтому всякий раз, когда пользователь нажимает клавишу на клавиатуре, Оливер запускает не одно событие keyPress, а три события KeyDown, событие KeyUp и вырезанное соло саксофона из восьмой симфонии Моцарта. Дражайшая Фиона, непреклонный трудоголик, проектирует свой браузер так, что когда вы «закрываете» его, графический интерфейс исчезает, но основной процесс крутится в фоновом режиме, тихо, злобно и медленно потребляя записи в таблицах ядра и делая невозможным перезапуск браузера без созерцания сообщения об ошибке «Где-то на белом свете работает другая копия браузера; найди Кармен СанДиего и она раскроет секрет». Любимый Кристофер, в попытке сделать свой браузер быстрым и легким, решает заменить его Flash-плагин кодом, который печатает «Shockwave упал», а затем сразу разыменовывает нулевой указатель; это гарантирует, что большинство ваших попыток посмотреть видео закончатся желанием более приземлённых зрелищ, типа резьбы по дереву или наскальной живописи. И бедный IE6, он же «из этого точно толка не будет, потому что IE6 не является правильным христианским именем», ухитряющийся как-то ковылять по миру, переживая больше покушений, чем Фидель Кастро.

Каждый браузер безрассуден и причудлив по-своему, но все браузеры одинаково разделяют любовь к эпичной подкачке на диск. Не редкий дождик из миниатюрных I/O, выровненных по границам размещения файловой системы, нет, я говорю о столкновениях снежных штормов чтения и записи, о первобытном потопе, заставляющем вас собирать своих соплеменников и решать, каких тварей брать по паре и не забыть ли огненных муравьев, ведь огненные муравьи портят лето. Браузерам не нужна конкретная причина для ушатывания диска, нет; подкачка — образ жизни браузеров, досуг, доставляющий сам по себе. Если вы не IT-специалист, вы просто смиряетесь с тем фактом, что посещение CNN.com заставит зеленую мигающую лампочку со значком цилиндра перестать мигать и светить зеленым постоянно. Однако, если вы таки знаете, как работают компьютеры, то бесконечная подкачка сводит вас с ума. Она превращает вас в Торквемаду — жалкую фигуру, одержимую страхом того, что вся ваша идеология — всего лишь вычурная ложь, нужная только лишь для того, чтобы скрыть чрезмерные дисковые операции серых кардиналов. Вы открываете ваш диспетчер задач, и обнаруживаете, что ваш браузер запустил 67 различных процессов, и все они называются «browser.exe», и все они отчаяннно палят изо всех I/O по таким загадочным областям файловой системы, как "\Roaming\горшки\сковородки\кэш\4$$Dtub.partial", где "\4$$" — экзотическая ESC-последовательность, раскрывающаяся в латвийский двойной умляут. Вы ищете в Интернете потенциальные решения и сталкиваетесь с кучей противоречивых и ничем не подкрепленных мнений: у вашего браузера вирус; у вашего вируса вирус; надо было использовать Emacs; надо было использовать vi, и именно поэтому ваш брак дал трещину.

Естественно, самый популярный совет для решения любых браузерных проблем — очистить кэш вашего браузера. Несомненно, очистка кэша иногда поможет, примерно так же, как пинание дерева нищебродом иногда приведёт к серии забавных событий, завершающихся падением на землю большого мешка с деньгами и запиской «Потрать всё! Цём, Жизнь.» К сожалению, пинание дерева, как правило, не приводит к богатству, так что ваш подкрепленный верой акт агрессии к деревьям на самом деле всего лишь делает вас диким, пинающим деревья монстром, порицаемом детьми и эмоционально чувствительными взрослыми. Аналогично, ваша внезапная очистка кэша браузера, несмотря на благие намерения, всего лишь местное болеутоляющее, ненадолго скрашивающее муки бытия. Исправление браузера очисткой кэша подобно вашему папе, подвозящему вас в детский сад, и, когда машина вдруг начинает дымиться, пытающемуся починить её тремя хлопками по капоту, а затем спрашивающему вас, чуете ли вы ещё монооксид углерода, и вы такой: «ага, уже лучше», потому что вам не хочется выставлять вашего папу жуликом, а затем вы оба проводите остаток пути молча, изо всех сил стараясь не потерять сознание.

Так что, да, было бы здорово, если бы исправление вашего браузера было связано с действиями, которые не были бы семантически эквивалентны вуду. Однако, с другой стороны, всё могло быть ещё хуже. Например, было бы действительно ужасно, если бы скриптовый язык вашего браузера сочетал в себе прототипное наследование Self, квазифункциональщину, позаимствованную из LISP, структурированный синтаксис, притянутый из C, и агрессивно-асинхронную модель ввода-вывода, требующую нетривиальных цепочек обратного вызова, охватывающих несколько поколений трудолюбивых американцев. О НЕТ, Я ТОЛЬКО ЧТО ОПИСАЛ JAVASCRIPT. Какой пренеприятный поворот событий! Люди жаждали комбинации Self, LISP и C столь же отчаянно, сколь жители Средиземья умоляли Сарумана скрестить орков с людьми, дабы получился Урук-хай. Орки и люди прекраснейше боролись за существование в своих отдельных общинах, создание новой расы с недостатками обоих — не самый лучший способ стать первым парнем на селе. Однако, несмотря на свои недостатки, JavaScript таки получил широкое распространение. Исследование причин сего подобно попыткам понять причины Первой мировой войны — все согласны с пятью основными причинами, но у всех своё мнение об их первостепенности. Суть такова: в 90-е годы, когда JavaScript и Java конкурировали за превосходство на клиенте, Java-апплеты были чудовищно медленны и не могли похвастаться взаимодействием с HTML; JavaScript же был только наполовину чудовищно медленен и мог паршиво (но мог) взаимодействовать с HTML. Так что Java проиграла, несмотря на:

  • JavaScript динамически типизирован, и его агрессивные правила приведения типов, похоже, были разработаны Monty Python. Например, 12 == «12», потому что строка приводится к числу. Это слегка тупо, но хотя бы имеет отдалённый смысл. А теперь рассмотрим тот факт, что null == undefined. Это полный бред; ссылка, указывающая на null, не может быть неопределенной, ОНА ПО ОПРЕДЕЛЕНИЮ УКАЗЫВАЕТ НА NULL. А теперь, когда вы размялись, посмотрите сюда: "\r\n\t" == false. Вот почему: браузер обнаруживает, что оба операнда имеют разные типы, поэтому он преобразует false к 0 и повторяет сравнение. Операнды всё еще имеют разные типы (строка и число), так что браузер приводит "\r\n\t" к числу 0, потому что с какого-то бодуна ненулевое количество символов равно 0. Вуаля — 0 равен 0! ШИКАРНО. Это объяснение подобно сюжету «Inception», за исключением того, что внедренной идеей было «корректность вашей программы приведена к false».
  • Здравствуй, добрый человек — дай мне согреть тебя этой холодной зимней ночью! Знаешь ли ты, что JavaScript определяет особое значение NaN («не число»)? Это значение является тем, что вы получаете, когда делаете такие глупости, как ParseInt(«БэтменНеЧисло»). Иными словами, NaN является значением, которое не является числом. Однако, typeof(NaN) возвращает… «число». Более логичным возвращаемым значением было бы «СЛАВА ВЕЛЬЗЕВУЛУ, ПОВЕЛИТЕЛЮ ТЬМЫ", но я отвлекся.
  • Кстати, NaN != NaN, так что Аристотель ошибался со всем этим «законом тождества».
  • Кроме того, JavaScript определяет два оператора тождественности (=== и !==), не выполняющих приведения типов, выполняемого стандартными операторами равенства; однако, NaN !== NaN. Короче, не используйте числа в JavaScript, а если уж у вас нет иного выхода, реализуйте программный ALU. Это медленно, но надёжно.
  • Хотя, на самом деле, недостаточно надёжно. В отличие от C++, использующего статическое описание интерфейсов класса, JavaScript использует прототипное наследование. Прототип представляет собой динамический объект, действующий как шаблон для «экземпляров» этого объекта. Например, если бы я захотел объявить класс Circle в JavaScript, я мог бы сделать что-то вроде этого:

    //Это конструктор, определяющий свойство "radius"
    //для новых экземпляров.
    function Circle(radius){
        this.radius = radius;
    }
    
    //Функция-конструктор содержит свойство объекта
    //под названием "prototype", определяющее дополнительные
    //атрибуты экземпляров класса.
    Circle.prototype.getDiameter = function(){
        return 2*this.radius;
    };
    var circle = new Circle(2);
    alert(circle.getDiameter()); //Выводит "4".

    Шаблоном объекта для класса Circle является Circle.prototype, и этот объект-прототип является обычным объектом JavaScript. Итого, путем динамического изменения свойств этого объекта, я могу динамически изменять свойства всех экземпляров этого класса. АГА, Я В КУРСЕ. Например, в какой-то случайный момент исполнениия моей программы, я могу сделать так…

    Circle.prototype.getDiameter = function(){
        return -5;
    };

    … и все мои круги будут думать, что их диаметр меньше, чем ничего. Это днище, но ещё хуже то, что прототипы предопределенных (или «родных») объектов JavaScript тоже могут быть переопределены. Так что если я сделаю что-то типа…

    Number.prototype.valueOf = function(){return 42;};

    … то любой числовой литерал, упакованный в объект Number, будет думать, что он ответ на главный вопрос жизни, вселенной, и всего такого:

    
    alert((0).valueOf());   //0 должен быть 0 для всех значений 0, но он 42.
    alert((1).valueOf());   //Зевс помоги, 1 тоже 42.
    alert((NaN).valueOf()); //NaN тоже 42. ОБЕЗГЛАВЬТЕ И СОЖГИТЕ МОЕ КОРЧАЩЕЕСЯ ТЕЛО

    Очевидно, что я получил то, что заслужил, если моя библиотека JavaScript переопределяет собственные прототипы, ломая мой собственный код. Однако, один-единственный фрейм веб-страницы содержит несколько библиотек JavaScript из нескольких источников, и кто его знает, какие ужасающие манипуляции с прототипами эти языческие библиотеки вытворяли перед запуском моей библиотеки. Это лишь одна из причин, почему от фразы «безопасность JavaScript» воспламеняются Библии.
  • Подобно C, JavaScript использует точку с запятой для завершения многих видов выражений. Однако, в JavaScript, если вы забыли точку с запятой, синтаксический анализатор JavaScript может автоматически вставить точку с запятой туда, где, по его мнению, эти точки с запятыми могли бы, возможно, обязаны, наверное, быть. Это кажется весьма полезным, пока вы не поймёте, что у точки с запятой есть семантический смысл. Вы не можете просто разбрасывать их вокруг, как будто вы Джонни Яблочное Зернышко от пунктуации. Автоматическая вставка точек с запятой в исходный код подобна игре в испорченный телефон, при условии, что каждое потерянное слово заменяется фразой «мать вашу». Это отличный способ освежить ваши межличностные отношения, но это не лучший способ парсить код. Некоторые библиотеки JavaScript намеренно начинаются с точки с запятой, чтобы гарантировать, что если вдруг эта библиотека будет дописана к другой (например, чтобы сократить количество HTTP запросов при загрузке), то синтаксический анализатор JavaScript не станет пытаться слепить последнее выражение первой библиотеки и первое выражение второй библиотеки в какую-то оргию выражений с точкой с запятой в качестве тамады. Такая начальная точка с запятой называется «защитная точка с запятой». Это самый печальный паттерн программирования, о котором я когда-либо слышал, и это при том, что я неплохо владею C++.

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

Итоги подведём — веб-браузеры подобны квантовой физике: в лучшем случае они предлагают вероятностные гарантии, а любой, кто утверждает, что полностью их понимает — лжец. На данном этапе развития человека есть более насущные проблемы: изменение климата, болезни сердца, плохое финансовое положение нигерийских принцев, желающих связаться с вами лично. Поскольку все эти проблемы не решены, просмотр веб-страниц — ужасный способ провести время; запуск нестабильных операционных систем, написанных для фана и загружающих странные файлы JavaScript от незнакомцев — последнее, чем нам стоит заниматься. Вместо этого нам стоит обмениваться информацией, используя ASCII сообщения фиксированной длины, написанные в статически проверяемом подмножестве латиницы, с изображениями, представленными в виде математических комбинаций отрезков линий, дуг и других вечных форм, описанных мертвыми философами, которые считали, что минотавры существуют, но не в силах выбраться из лабиринтов. Именно такое ясное мышление поможет нам победить космических египтян, выходящих из Звездных Врат. Ну или как там. Я американец и не силен в истории, но я твердо верю, что греки говорили на латыни, чтобы победить межгалактических египтян. #ДаешьПолемику! Короче, я хочу сказать, что браузеры слишком сложны, чтобы им доверять. К сожалению, дети тратят молодость впустую, и нынешнее поколение разработчиков программного обеспечения убеждено, что браузерам нужно больше фич, а не меньше. Так что нам предлагается возрадоваться тому, что браузеры превращают наши компьютеры в маленькие таверны из «Звездных войн», где рады каждому, и где вы можете выпить синего пойла, если вам хочется выпить синего пойла, и если что-то пойдет не так, то, возможно, джедай спасет вас, а если нет, ЭТО ЖЕ ТАВЕРНА ИЗ ЗВЕЗДНЫХ ВОЙН, ДААААА. Космические таверны хороши, но это фантастика; это просто куча сшитых вместе нелепых деталей для увеселения публики. Откройте глаза и узрите, что в реальном, негиперболичном мире, в котором вы живете, ваш браузер будет то и дело прерывать видео, а затем показывать мигание эпилептичных пикселей, издавая тот же звук, что издают телевизоры в японских фильмах ужасов перед тем, как бледное дитё сойдет с экрана и лишит вас гарантии. Это может произойти на самом деле, и мы должны всё это смыть.
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 161

    +13
    Люблю запах неконструктивного нытья поутру.
      –10

      А с учётом того, что у автора, похоже, случился словесный понос, то и запашок посильней кофейного.

        +12
        ну да, надо смириться и дебажить. Давайте еще скажем, что IPv6 не нужон, нужно просто «конструктивно» напихать в интернет NAT'ов побольше. Как раз-таки называние вещей своими именами и пропаганда нетерпимости к легаси-бреду может дать толчок к уходу в более адекватную сторону в будущем.

        Вообще, глядючи на Ваш профиль, вы видимо предельно далеки от фронтэнда. Но вообще мне (как кандидату физматнаук) просто дико удивительно, как человек, который посвятил жизнь алгоритмам, где все заточено на оптимизацию, внезапно называет критику зоопарка HTML/CSS/браузерной совместимости неконструктивной. Казалось бы, хаос как он есть и плевок в лицо всем оптимизаторам, которые трудятся в том числе и для того, чтобы достаточно быстро отрендерить всю ту дрянь, которая напихана в спеках без всякого интереса к тому, удобно ли будет с этим работать. Где Ваше стремление к оптимальности? Мой опыт говорит, что хреново задизайненные вещи приходится оптимизировать целую вечность. А хорошо задизайненные — не приходится в общем-то.

        Нерелевантно лично для вас, но неясно, почему неконструктивно. Я понимаю, что чтение препринтов на архиве приучает к выдающейся сухости письменного языка, но с точки зрения презентации — эта будет как минимум очень запоминающейся, это высший класс журналистики и презентации. Это навык. Ученым сложно понять. Но такой текст прочтут в тысячи раз больше людей, чем ваш или мой.
          +5
          Объясняю. Конструктивная критика — это когда предлагаются пути решения проблем. Без этого это в лучшем случае объективная критика, но никак не конструктивная. «Выкинуть всё и задизайнить заново» — не путь решения проблемы.

          P. S. Я не посвящал свою жизнь алгоритмам. Меня волнует счастье пользователей, а оно не так сильно связано с оптимизацией, как многим хотелось бы.
            0
            Но проблема-то не техническая! Очевидно, что сделать веб 3.0 с какими-нибудь стандартными json вместо HTTP Codes не проблема. Проблема в головах, в тех головах, которые требуют поддержки IE древних версий. И сам факт пропаганды необходимости уходить от трэша — он уже, на мой взгляд, сам по себе часть решения.
              +4
              Где вы видели такие головы, которые требуют поддержки IE древних версий? Мне чаще встречается «наш сайт некорректно выглядит в firefox? используйте хром для просмотра нашего сайта, пожалуйста.»
                +1
                Хехе, только недавно я жаловался своему банку, что их страница для восстановления забытого пароля не работает в Chrome.
                Ответили: «мы знаем, используйте IE».
            0
            Проблема в легаси, инерции и популярности. Хотя это толком и не проблема даже, а скорее следствие. Слишком большое количество людей начали использовать все эти технологии, и тянуть их в разные стороны, натягивая дальше и дальше это все на глобус. Поэтому и тезисы в статье неконструктивные, — я бы даже сказал, инфантильные. Веб реализует постоянно меняющиеся потребности миллиардов людей во многом благодаря тому, как именно он развивается.
              0
              Рискну предположить, что от наличия менее безумных решений веб не пострадал бы никак. «После этого не значит вследствие этого». В масштабах мелкой фирмы такой зоопарк быстро бы все обанкротил, а в масштабах мира почему-то это сразу благо, если следовать вашей логике.
          +6
          ух какая простыня, аж глаза слезятся
            +22

            Перевод просто шикарен :)

              +4
              люто, бешено плюсую. Переводчик великолепен.
                0
                because you didn’t want to expose your dad as a fraud
                потому что вам не хочется выставлять вашего папу жуликом

                "Жулик" тут совсем не к месту. Может, "самозванец" или перефразировать с "некомпетентный"…

                  +4

                  И всё же местами потерялось многое, из-за ограничений самого хабра.


                  Например


                  «Если результат недействителен ([SELECT], раздел 12), следует бросить исключение SYNTAX_ERR ([DOM-LEVEL-3-CORE], раздел 1.4) и прервать этот алгоритм». Подобный романтический этюд в канцелярских тонах, несомненно, будет по нраву людям, тоскующим по тупости списка ингредиентов Доширака, помноженного на многослойную бюрократию Советского Союза. Действительно, можно представить себе мир, в котором производители браузеров нанимают легионы толкователей Талмуда, дабы понять, почему SYNTAX_ERR именно оранжевый, а не лиловый, и как именно эта оранжевость относится к оскобоченной лиловости ([DOM-LEVEL-3-CORE]).

                  Оригинал:


                    +4
                    Но ведь хабр позволяет раскрашивать цвет разными цветами.
                      +1

                      Точно. Возможно, автор учтет это и поправит пост.

                  +41
                  Разделяя в целом нелюбовь автора к Javascript, не могу не заметить, что автор перегибает палку:
                  Знаешь ли ты, что JavaScript определяет особое значение NaN («не число»)?
                  Особое значение, а точнее множество значений «Not A Number», определяет не Javascript, а стандарт IEEE 754, которому кое-как пытаются следовать все языки программирования.
                  NaN != NaN, так что Аристотель ошибался со всем этим «законом тождества».
                  Аристотель был бы в шоке, если бы узнал что занимался проектированием арифметики чисел с плавающей запятой для интегральных схем. Поведение Javascript в данном случае полностью соответсвует стандарту:



                  И если кого-то пугает не выполнимость закона тождества (а также транзитивности, линейной упорядоченности, и еще кучи законов) для чисел с плавающей запятой (а других в Javascript нет), то добро пожаловать в этот мир. У нас тут еще есть -0 и +0, которые как бы равны, но выдают разные результаты при вычислении над ними.
                    +5

                    А стандарт определяет NaN таким образом, потому что в Intel 8087 не было инструкции ассемблера isnan. И было не ясно не откажутся ли производители процессоров от стандарта, если её ввести. https://stackoverflow.com/a/1573715/2731452

                      +3
                      По ссылке отличный рассказ, но вы его не вполне верно поняли.
                      В Intel 8087 всё было (младший бит в регистре флагов означал, что результат последней операции — NaN), но примитива isnan не было ни в одном из существовавших языков программирования.
                        0
                        Если бы у правила NaN != NaN не было собственного смысла, сработавшего как мощный аргумент «за», никакое отсутствие isnan() не помогло бы.
                          +1

                          Мой ответ уже поправили. Самый мощный аргумент — отсутствие поддержки isnan и литерала NaN в популярных на то время языках программирования. А с введением предиката totalOrder в 2008-м году, без NaN != NaN уже можно спокойно обойтись.

                            0
                            > А с введением предиката totalOrder в 2008-м году, без NaN != NaN уже можно спокойно обойтись.

                            Ой сомневаюсь. Как раз оригинал про totalOrder:

                            3) If x and y are both NaNs, then totalOrder reflects a total ordering based on:
                            i) negative sign orders below positive sign
                            ii) signaling orders below quiet for +NaN, reverse for −NaN
                            iii) lesser payload, when regarded as an integer, orders below greater payload for +NaN,
                            reverse for −NaN.


                            Поэтому всё пройдёт только при дополнительном условии — все NaN канонизированы — что, в общем случае, не верно. Иначе получится, что +qnan(0) < qnan(1), qnan(x) != snan(x) для любого x>0, и так далее.
                            Total ordering в IEEE754-2008 нацелен не на лечение проблемы с NaN, а на решение проблемы несравнимости чисто формальным введением сравнения :(

                            > Самый мощный аргумент — отсутствие поддержки isnan и литерала NaN в популярных на то время языках программирования.

                            Ну вот я объяснил, почему я не считаю его «самым мощным»: без реального смысла за таким результатом сравнения он был бы ничтожен.
                              0
                              Насколько я понял из рассказа, реальный смысл стандартизаторам виделся как за результатом NaN != NaN, так и за результатом NaN == NaN, поэтому решающим аргументом стала поддержка в ЯП.
                            0

                            У него нет собственного смысла. NaN — это как Nothing. А Nothing таки равен Nothing (того же типа).

                              0
                              > NaN — это как Nothing. А Nothing таки равен Nothing (того же типа).

                              netch@localhost [(none)]> select null = null;
                              +-------------+
                              | null = null |
                              +-------------+
                              | NULL |
                              +-------------+
                              1 row in set (0.02 sec)

                              netch@localhost [(none)]> select null is null;
                              +--------------+
                              | null is null |
                              +--------------+
                              | 1 |
                              +--------------+
                              1 row in set (0.00 sec)



                              Это из MySQL, но в других SQL СУБД будет похоже. Так что эта традиция достаточно древняя и почтенная :)

                              Равенство != идентичность содержания, а как минимум в JS лёгкой проверки на второй не завезли (и, более того, '===', который должен был быть identity check, превратили в нечто заметно другое).
                                0
                                Равенство != идентичность содержания

                                А какое из этих отношений у вас включается в какое и в каких контекстах?


                                ИМХО из равенства следует идентичность содержания. А в языках без возможности взять адрес они вообще скорее эквивалентны. Да и в том, чтобы в языках с адресами их сделать эквивалентными, я тоже не вижу проблемы.

                                  +2
                                  > А какое из этих отношений у вас включается в какое и в каких контекстах?

                                  В том и проблема, что в современной плавучке ни одно из них не включается в другое.
                                  qnan(0) != qnan(0), несмотря на идентичность.
                                  +0.0 == -0.0, несмотря на неидентичность.

                                  > ИМХО из равенства следует идентичность содержания.

                                  +0.0 == -0.0.

                                  Да, это многих сбивает при изучении вопроса.

                                  А в десятичной плавучке, где нормализация необязательна, и при значениях не 0 и не NaN могут быть равные значения с разным порядком (и поэтому по-разному воздействующие при операции quantize).

                                  > А в языках без возможности взять адрес они вообще скорее эквивалентны.

                                  В Java можно взять адрес? (хаки не считаем)

                                  Вполне может быть, что a != b, но a.equals(b) == true.
                                  Да, этой грабле тоже надо учиться — как отвыкать сравнивать строки на `=='.
                                    0

                                    Это всего лишь значит, что IEEE754 врёт во многих местах.


                                    Битовые паттерны меня не очень интересуют, если я (без хаков) не могу их наблюдать. Но если +0 и -0 ведут себя по-разному в некоторых контекстах, то они не равны. Ну и аналогично с остальными фичами.


                                    В Java можно взять адрес? (хаки не считаем)
                                    Вполне может быть, что a != b, но a.equals(b) == true.

                                    Java — не образец sound-языка.

                                      +1
                                      > Битовые паттерны меня не очень интересуют, если я (без хаков) не могу их наблюдать.

                                      Можете. Например, в C <math.h> есть fpclassify(), signbit(), copysign(), frexp(), ldexp(). Сам стандарт даёт те же методы. Любое значение можно проанализировать, разложить, создать заново. Единственно что — я не вижу методов работы с NaN payload — но это редкая необходимость.

                                      > Это всего лишь значит, что IEEE754 врёт во многих местах.

                                      Где это он врёт и почему? С чего вы это взяли?

                                      > Но если +0 и -0 ведут себя по-разному в некоторых контекстах, то они не равны.

                                      Да, ведут себя по-разному. Например:

                                      atan2(±0, −0) is ±π
                                      atan2(±0, +0) is ±0

                                      Это неудивительно, если рассматривать специфику некоторых функций и то, что 0 == 1/inf в понимании стандарта.

                                      > Java — не образец sound-языка.

                                      Такие проблемы (возможно, с переименованием операций) неизбежно возникают в любом языке на ссылках. Но есть те, что показывают открыто, а могут быть и те, что маскируют. Если вы знаете какой-то другой язык, где не различают идентичность и равенство, значит, там будут спрятаны грабли.
                                        0
                                        Можете. Например, в C <math.h> есть fpclassify(), signbit(), copysign(), frexp(), ldexp(). Сам стандарт даёт те же методы. Любое значение можно проанализировать, разложить, создать заново. Единственно что — я не вижу методов работы с NaN payload — но это редкая необходимость.

                                        Так-то я могу и memcpyнуть его в char[sizeof(double)], понятное дело.


                                        Это неудивительно, если рассматривать специфику некоторых функций и то, что 0 == 1/inf в понимании стандарта.

                                        Но это математически некорректно!


                                        Где это он врёт и почему? С чего вы это взяли?

                                        Ну вот например там, где ноль — это не ноль, а непонятно что.


                                        Если вы знаете какой-то другой язык, где не различают идентичность и равенство, значит, там будут спрятаны грабли.

                                        С радостью обсужу. Какого рода грабли мне там ждать?

                                          +1
                                          > Так-то я могу и memcpyнуть его в char[sizeof(double)], понятное дело.

                                          Но тогда вы привязываетесь сразу на толпу фактов — на представление в IEEE754 обменном формате (в курсе, что внутренний формат имеет полное право отличаться?), на порядок байт и даже r
                                          на сам размер байта. Ну да, для 4-5 основных платформ будет действовать.

                                          > Но это математически некорректно!

                                          Ну если воспринимать математику по-школьному — да.
                                          Но есть другие подходы: например, вещественные вместо числовой оси могут представляться как числовое кольцо, при этом +INF и -INF сходятся в одной точке (INF), а реально +INF это INF-0 (бесконечно близкое, но не совпадающее значение). Такой подход даётся, например, в типовом курсе «Теория функций комплексного переменного», где через него строится много следующих выводов (хотя это ещё интерпретация действительного, а не комплексного, числа). Вы, видимо, его не учили, раз так удивляетесь?

                                          UPD: вы рядом упомянули «нестандартный анализ». Я очень вскользь помню, что это, но, кажется, там идея числового кольца не входила.

                                          > Ну вот например там, где ноль — это не ноль, а непонятно что.

                                          Как раз понятно что: «ноль или слишком малое значение», у которого сохранён знак приближения к нулю. Точно так же у INF сохранён знак как указание стороны, с которой приблизились к бесконечности.

                                          Возьмём уже названый пример с atan2: atan2(0, +x) равен 0, но atan2(+0, -x) равен +π для любого неотрицательного x, включая 0. Это очень просто понять, если посмотреть на поведение задачи вычисления угла (а заодно на график арктангенса: где какие разрывы в графике). Нужно было по-вашему делать исключение типа «в нуле вообще нет определения функции»?

                                          > Какого рода грабли мне там ждать?

                                          Всё те же — в реальных задачах требуется проверка идентичности и равенства всего, что не просто плоское значение без поведения; это разные операции.
                                            0
                                            Но тогда вы привязываетесь сразу на толпу фактов — на представление в IEEE754 обменном формате (в курсе, что внутренний формат имеет полное право отличаться?), на порядок байт и даже r
                                            на сам размер байта. Ну да, для 4-5 основных платформ будет действовать.

                                            Да. Но речь шла о наблюдении битов с точки зрения обычных арифметических операций.


                                            Такой подход даётся, например, в типовом курсе «Теория функций комплексного переменного», где через него строится много следующих выводов (хотя это ещё интерпретация действительного, а не комплексного, числа). Вы, видимо, его не учили, раз так удивляетесь?

                                            Вот люблю, когда люди начинают так выпендриваться, это всегда обещает интересную дискуссию.


                                            Давайте мы с вами возьмём фактор-кольцо ℝ[x] по идеалу, порождённому x² + 1, и вы мне покажете, где там возникает хоть какая-нибудь бесконечность как элемент этого фактор-кольца.


                                            Как конкретно строилось аксиоматизировалось множество комплексных чисел у нас в ТФКП, я, признаться, не помню, за 10 лет как-то забылось, но это и неважно, там получатся изоморфные вещи.


                                            Я очень вскользь помню, что это, но, кажется, там идея числового кольца не входила.

                                            Верно, не входила.


                                            Всё те же — в реальных задачах требуется проверка идентичности и равенства всего, что не просто плоское значение без поведения; это разные операции.

                                            Так в каких реальных задачах-то это требуется?

                                              0
                                              > Вот люблю, когда люди начинают так выпендриваться, это всегда обещает интересную дискуссию.

                                              А я — нет. Потому что нет никакого «выпендривания», есть просто попытка объяснить чужую логику. Ваша оценка моих действий больше вас характеризует, чем меня.

                                              > Давайте мы с вами возьмём фактор-кольцо ℝ[x]

                                              Не давайте. Речь не о «кольце» в смысле теории групп, речь об отображении на банальную окружность на плоскости. Наверно, лучше было сразу сказать «окружность», просто я уже вспоминал это кусками и за 25+ лет тому назад.
                                              Отображаем (-inf, +inf) на (-1, +1), а его — на окружность единичного радиуса, например, так, что 0 мапится в (1,0); 1 — в (0,1); inf — в (-1,0); -1 — в (0,-1); если u имеет координаты (x,y), то 1/u — (-x,y).
                                              Там дальше это развивалось в том, что аналогичное построение для комплексных чисел давало сферу в трёхмерном пространстве, и на этой сфере вводились интересные топологические результаты. Но я уже не хочу искать это по книгам, моя область сейчас резко далека от всего этого, увы.

                                              > Так в каких реальных задачах-то это требуется?

                                              Я лучше поставлю встречный вопрос: вы знаете язык, в котором одновременно присутствовали бы указатели или ссылки (тут разница неважна) с возможностью сравнения на равенство, и возможность задавать сравнение по содержанию для своих типов, и не было бы разницы между этими двумя действиями?
                                              Если да, и этот язык хоть как-то жив за пределами трёх инвалидов — назовите. По-моему, даже в лиспах есть возможность такой проверки.
                                              Да, я считаю правильным ставить вопрос именно так. Наверно, можно сделать и без контроля идентичности — но будет заметно дороже.
                                                0
                                                Речь не о «кольце» в смысле теории групп, речь об отображении на банальную окружность на плоскости. Наверно, лучше было сразу сказать «окружность», просто я уже вспоминал это кусками и за 25+ лет тому назад.

                                                Я понял, в каком оно там смысле (в «обыденном», а не алгебраическом). Но никаких бесконечностей как элементов \mathbb C там не возникает, только и всего.


                                                Отображаем (-inf, +inf) на (-1, +1), а его — на окружность единичного радиуса, например, так, что 0 мапится в (1,0); 1 — в (0,1); inf — в (-1,0); -1 — в (0,-1); если u имеет координаты (x,y), то 1/u — (-x,y).

                                                Обратите внимание — (-inf, +inf), а не [-inf, +inf], такая запись (с открытым интервалом и невключёнными границами) там неспроста. inf у вас никуда не мапится, потому что его нет в домене.


                                                Я лучше поставлю встречный вопрос: вы знаете язык, в котором одновременно присутствовали бы указатели или ссылки (тут разница неважна) с возможностью сравнения на равенство, и возможность задавать сравнение по содержанию для своих типов, и не было бы разницы между этими двумя действиями?

                                                Зависит от того, считаете ли вы хаскель языком с ссылками, например.

                                                  0
                                                  > Обратите внимание — (-inf, +inf), а не [-inf, +inf], такая запись (с открытым интервалом и невключёнными границами) там неспроста. inf у вас никуда не мапится, потому что его нет в домене.

                                                  В ℝ — да. Но если сделать маппинг, то появляется одна исключённая точка — а зачем такое нужно? Сделаем для неё значение (тогда левая сторона маппинга будет ℝ+{inf}). Это тоже явно оговаривалось. Увы, я ж говорю — давно было.

                                                  > Зависит от того, считаете ли вы хаскель языком с ссылками, например.

                                                  Для простоты будем считать, что я его совсем не знаю. И чего именно в нём нет? Проверки на идентичность, по общей логике? Боюсь, где-то на границе с реальным миром она должна появиться.
                                                    0
                                                    Сделаем для неё значение (тогда левая сторона маппинга будет ℝ+{inf}).

                                                    Эта запись не имеет смысла, потому что нет такого элемента, как inf.


                                                    Вы вольны пополнять множество как хотите, конечно, но это уже будет совсем другой вопрос (и, скорее, носящий иллюстративный характер — ТФКП спокойно строится без добавления всех этих бесконечностей).


                                                    И чего именно в нём нет? Проверки на идентичность, по общей логике? Боюсь, где-то на границе с реальным миром она должна появиться.

                                                    Если у вас даны два Int (или два значения произвольного типа вроде data Foo = Foo { smth :: Int, smthElse :: String, someList :: [Foo] }), то вы не сможете определить, являются ли они на самом деле одним и тем же значением в памяти или нет, даже если их значения равны.


                                                    На границе с реальным миром идёт маршаллинг, и вы свои чистые значения преобразуете в что-то, что имеет адреса и может быть передано в сишный код, но даже два последовательных преобразования одного и того же терма могут дать разные адреса, если постараться, так что это тоже ни о чём не говорит.

                                              +2
                                              Но есть другие подходы: например, вещественные вместо числовой оси могут представляться как числовое кольцо, при этом +INF и -INF сходятся в одной точке (INF)
                                              Вам возможно будет интересно, что именно такой подход используется для определения вещественных чисел в стандарте Posit (который задуман как альтернатива IEEE754):

                                                0
                                                Я видел posit, но считаю его провальным из-за неравномерной точности.
                                                Вообще, надо смотреть на возможное качество реализации в железе и на полный набор эффектов… но я очень сомневаюсь, что переход окупится.
                                                  0

                                                  У меня на планшете уже почти год открыты статьи по posit, надо бы их, наверное, наконец, прочитать.

                                                +2
                                                Это неудивительно, если рассматривать специфику некоторых функций и то, что 0 == 1/inf в понимании стандарта.
                                                Но это математически некорректно!
                                                Это корректно даже с чисто математической точки зрения. Infinity, по определению стандарта, это аппроксимация любого вещественного числа, которое больше чем (2−2^−23)×2^127 (для одинарной точности).

                                                И если вы поделите единицу на любое из этих чисел, вы получите число, отличное от нуля, но оно будет апроксимировано к тому что IEEE754 определяет как +0.

                                                Все становится гораздо логичнее, если относиться к каждому значению IEEE754 не как к точке на прямой вещественных чисел, а как к интервалу вещественных значений.

                                                Значения +0 и -0 это не точки на вещественной прямой, а два разных интервала вещественных чисел слева и справа от нуля. И это единственная пара интервалов из всех возможных значений IEEE754, которая имеет пересечение (в точке 0). Именно по-этому -0 == +0.
                                                  +1

                                                  Так "==" — это "равно" или "интервалы пересекаются"? Или мы заменяем равенство на "хотя бы частично интервалы пересекаются"?

                                                    0
                                                    Строго говоря, мы не можем определит «честное равно» между вещественными числами, выраженными в IEEE754, просто потому что мы используем конечное множество значений чтобы выразить бесконечное множество чисел. Это означает, что мы теряем точность представления и у нас появляется погрешность.

                                                    Представьте что вы измерили вольтметром напряжение два раза, и вас получились значения 5.0±0.2 и 5.1±0.1. Эти значения «равны» или «не равны»?

                                                    Каждое значение IEEE754 – это некоторый интервал вещественных значений, и мы можем говорить лишь о пересечении этих интервалов. Другое дело, что почти все пары интервалов либо совпадают полностью, либо не пересекаются вообще, и только интервалы -0 и +0 являются исключительным случаем – имеют пересечение в точке ноль.

                                                    Но все эти размышления являются скорее моей вольной интерпретацией стандарта, основанные на знаниях как устроены другие системы представления чисел с плавающей запятой. У авторов IEEE754 скорее всего есть собственное более прагматичное объяснение почему все функции определены так как определены.
                                                    0
                                                    Все становится гораздо логичнее, если относиться к каждому значению IEEE754 не как к точке на прямой вещественных чисел, а как к интервалу вещественных значений.

                                                    А это интересный взгляд!


                                                    Но я сходу так не уверен, что интервальная арифметика в терминах IEEE754 всё равно будет осмысленной.

                                              0
                                              Вполне может быть, что a != b, но a.equals(b) == true.
                                              Да, этой грабле тоже надо учиться — как отвыкать сравнивать строки на `=='.

                                              Ну вот это кстати совсем не «грабля» а вполне себе понятная особенность языка. Ссылочные типы и всё такое.
                                                0
                                                Значит, в JS строки не ссылочный тип, раз там они сравниваются по содержимому, в отличие от остальных объектов?
                                                  0
                                                  Если я всё правильно помню, то в JS стринги передаются by value.
                                                  +1
                                                  Для сравнения, в C# и в Python оператор "==" для строк переопределён для сравнения содержимого на равенство. Но при этом можно сравнить и сами ссылки, если хочется.
                                          +1
                                          У него нет собственного смысла. NaN — это как Nothing. А Nothing таки равен Nothing
                                          Вы не правы. NaN – это совсем не тоже самое что Nothing/Null/None.

                                          IEEE754 определяет множество значений, которым могут выражаться рациональные числа, но не все возможные значения IEEE754 являются числами: NaN, +Infinity и -Infinity не являются числами, хоть и являются корректными значениями типа.

                                          Операции порядка и тождества (>, >=, <, <=, ==, !=) могут быть определены над разными множествами (числа, строки, и т.д.), но далеко не для любого множества выполняется свойство полной упорядоченности (total ordering) и далеко не всегда значение тождества может быть определено для всех пар элементов множества.

                                          Посмотрите на это с точки зрения математики: равна ли «бесконечность» самой себе либо бесконечности полученной другим образом, например умножением первой бесконечности на 2?

                                          Большинство языков программирования ожидают что функции сравнения и тождества (>, >=, <, <=, ==, !=) всегда должны возвращать только булевое значение (true/false).

                                          Ошибочно полагать, что если «a < b» возвращает false, то это означает что a не меньше чем b. Это означает что ответ на вопрос «is a less than b» является false. Это так же означает, что результатом выполнения «a > b» так же может быть false, просто потому что между значениями a и b нет отношения порядка.

                                          Довольно удачно на мой взгляд эта концепция реализована в Rust, где есть интерфейс Ord (для полностью упорядоченных множеств), и PartialOrd (для множеств, между которыми может быть установлен только частичный порядок, как числа с плавающей запятой):

                                          trait PartialOrd {
                                              fn partial_cmp(&self, other: &Self) -> Option<Ordering>;
                                          }

                                          Таким образом, если вы попытаетесь выяснить отношение порядка для двух значений чисел с плавающей запятой, у вас может быть четыре варианта результата: Some(Ordering::Less), Some(Ordering::Equal), Some(Ordering::Greater) и None.

                                          И если вы сравните NaN и NaN в Rust, то результатом сравнения будет None, поскольку между этими значениями нет установленной упорядоченности – они не равны, не меньше, и не больше друг друга.
                                            0
                                            Вы не правы. NaN – это совсем не тоже самое что Nothing/Null/None.

                                            В IEEE754 — да, не то же самое. Но я не вижу адекватных причин так делать в 2020-м году, и я говорю, если хотите, о желаемой для себя модели. Извините, что неясно написал.


                                            Операции порядка и тождества (>, >=, <, <=, ==, !=) могут быть определены над разными множествами (числа, строки, и т.д.), но далеко не для любого множества выполняется свойство полной упорядоченности (total ordering) и далеко не всегда значение тождества может быть определено для всех пар элементов множества.

                                            Для какого множества отношение тождества не может быть определено для всех пар элементов?


                                            А множества без линейного порядка не получится, например, отсортировать. А сортировать флоаты всё-таки хотелось бы.


                                            Чем больше ограничений и требований вы накладываете на алгебраическую структуру, тем с ней проще работать. Избегая требования линейного порядка на флоатах вы выигрываете… что?


                                            Посмотрите на это с точки зрения математики: равна ли «бесконечность» самой себе либо бесконечности полученной другим образом, например умножением первой бесконечности на 2?

                                            В классическом анализе у меня нет формального понятия бесконечности, она не принадлежит R (или Q, или N). В нестандартном анализе бесконечность есть, и она вполне равна себе, и её вполне можно умножить на два.


                                            Так что тут либо крестик (и у вас есть +infty, -infty, и на самом деле очень много разных infty, которые вполне конкретно сравнимы и упорядочиваемы), либо трусы (бесконечность нельзя сравнивать саму с собой — но это уже синтаксически некорректно).

                                              +2
                                              Но я не вижу адекватных причин так делать в 2020-м году
                                              Единственная причина делать так в 2020 – огромное количество алгоритмов ожидает именно такого поведение NaN, как бы всем нам это не нравилось.
                                              Для какого множества отношение тождества не может быть определено для всех пар элементов?
                                              В понимании IEEE754, значение тождества не определено для тех пар чисел с плавающей запятой, у которых хотя бы одно из значений является NaN. Ну и тут еще пару более абстрактных примеров.
                                              А множества без линейного порядка не получится, например, отсортировать. А сортировать флоаты всё-таки хотелось бы.
                                              Ох, не мне вам об этом рассказывать:
                                              fn main() {
                                                  let x = [3.0, 2.0, 1.0];
                                                  x.sort()
                                              }

                                              И результат:
                                              error[E0277]: the trait bound `{float}: std::cmp::Ord` is not satisfied
                                               --> src/main.rs:4:7
                                                |
                                              4 |  x.sort()
                                                |    ^^^^ the trait `std::cmp::Ord` is not implemented for `{float}`

                                              Да, в Rust нельзя просто взять и отсортировать массив флоатов, до свидания.

                                              Насколько я знаю, в других ЯП реализации алгоритмов в стандартных библиотеках используют хаки только ради того, чтобы не сходить с ума от бесконечных перестановок NaN. Rust пошел более жестким путем и тупо запретил все алгоритмы, которые требуют total ordering для float. То есть, float не может быть ключом в бинарном дереве или хеш таблице – система типов не позволит.

                                              Избегая требования линейного порядка на флоатах вы выигрываете… что?
                                              В некоторых случаях именно такое поведение NaN упрощает реализацию алгоритмов. Например, если я ищу перебором минимальное и максимальное значение в цикле, я знаю что вариант NaN никогда не будет ни больше, ни меньше всех остальных кандидатов. В противном случае пришлось бы добавлять дополнительную проверку.

                                              В классическом анализе у меня нет формального понятия бесконечности, она не принадлежит R (или Q, или N). В нестандартном анализе бесконечность есть, и она вполне равна себе, и её вполне можно умножить на два.

                                              Так что тут либо крестик (и у вас есть +infty, -infty, и на самом деле очень много разных infty, которые вполне конкретно сравнимы и упорядочиваемы), либо трусы (бесконечность нельзя сравнивать саму с собой — но это уже синтаксически некорректно).
                                              Тут я с вами полностью согласен, и на мой взгляд в IEEE754 бесконечность та, которая с трусами и без крестика, просто потому что значение бесконечности есть, а кардинальные числа в стандарт не завезли.

                                              Но IEEE754 со мной не вполне согласен, потому что с их точки зрения бесконечности – это вполне себе числа, в том смысле, что эти значения выражают наилучшую из возможных аппроксимаций вычислений.

                                              То есть это не бесконечности в математическом смысле слова, а множество всех (конечных) значений за пределами динамического диапазона аппроксимированные в два конкретных значения. Точно так же, как множество всех бесконечно малых и близких к нулю значений аппроксимируются в два конкретных значения – +0 и -0.

                                              Так что в IEEE754 бесконечность это число, и она равна сама себе, а NaN – нет.
                                                +2
                                                > Насколько я знаю, в других ЯП реализации алгоритмов в стандартных библиотеках используют хаки только ради того, чтобы не сходить с ума от бесконечных перестановок NaN.

                                                Хаки — нет, а вот специфический подбор алгоритма — да. В каком-нибудь qsort не любой метод разделения подходит.

                                                Это интересная тема, кстати, с точки зрения именно алгоритмов. Хотя на интервью лучше не надо :)
                                              0
                                              > Довольно удачно на мой взгляд эта концепция реализована в Rust, где есть интерфейс Ord (для полностью упорядоченных множеств), и PartialOrd (для множеств, между которыми может быть установлен только частичный порядок, как числа с плавающей запятой):

                                              А вот тут вопросик всплывает: у float есть определение тотального порядка, хоть оно и странное. Стандарт 2008 года уже требует поддержки такого сравнения. Как реализовывать такое при таком типаже? Отдельная функция? Я быстрым поиском нашёл такое и такое, но не знаю, насколько они каноничны и соответствуют духу языка (уже факт двух параллельных реализаций смущает).
                                                +1

                                                Так там же прямо написано, что обёртки упорядочивают по разному: первое считает NaN больше всех остальных чисел, а второе считает положительный NaN больше положительной бесконечности и отрицательный NaN меньше отрицательной бесконечности.

                                                  +1
                                                  Да, есть такое (второй соответствует требованиям IEEE754-2008 на total ordering, первый — нет). Но это аж никак не отвечает на мои вопросы.
                                                    +1
                                                    Если бы (гипотетически) стандарт изменил поведение сравнения с NaNs, то все что нужно было бы сделать, это добавить в стандартной библиотеке реализации типажей Eq и Ord для f32 и f64, и все алгоритмы магическим образом заработали. Это если закрывать глаза на нарушение обратной совместимости.

                                                    Но так как стандарт не изменяет правила сравнения чисел, а лишь добавляет новую функцию totalOrder, то просто так реализовать Ord/Eq по правилам totalOrdering нельзя, поскольку документация Rust прямо требует, что имплементации Ord/Eq/PartialOrd/PartialEq обязаны быть взаимно согласованы, а мы не можем этого гарантировать, поскольку totalOrder(NaN, x) выдает один результат, а (NaN < x) выдает другой результат.

                                                    Конечно, можно (и наверное нужно) добавить новые функции f32::total_order(self, other), но само их добавление мало улучшит жизнь разработчикам, потому что все алгоритмы полагаются на типажи Ord/Eq, которые, как мы выяснили, мы не можем реализовать для f32/f64.

                                                    Единственный выход, который остается – добавлять новые типы-обертки вроде тех что вы нашли в стандартную библиотеку, и реализовывать так же все семейство типажей From/TryFrom/Into/Borrow/AsRef/AsMut/Deref/DeferMut, чтобы компилятор во всех случаях сам додумывался запаковывать/распаковывать обертки.

                                                    Поскольку в Rust у нас принцип «zero-cost abstraction», эти обертки никак не будут отражаться на производительности программ, и существовать только на уровне системы типов во время компиляции.
                                                      0
                                                      > Но так как стандарт не изменяет правила сравнения чисел, а лишь добавляет новую функцию totalOrder

                                                      Мнэээ… именно в стандарте, формально новый тип сравнения — наравне со старым, он просто другой для других целей.

                                                      С ним получается три вида сравнений: ordered (наличие NaN хотя бы с одной стороны создаёт исключение), unordered (NaN с любой стороны даёт несравнимость, то есть любой предикат сравнения даёт false, но без создания исключения) и total. По умолчанию в большинстве языков (в Rust тоже)? классические сравнения — "==" и "!=" — unordered, а "<", "<=", ">", ">=" — ordered, поэтому про их отличие так сходу со стороны и не заметно. Но в более тонких случаях приходится вспоминать и про них.

                                                      Видимо, потому и надо закостыливать, что система типов не позволяет иметь три разных вида сравнения для одного типа? Но тогда и пожелание сделать, например, unordered "<" будет реализовываться такими же костылями.

                                                      > Единственный выход, который остается – добавлять новые типы-обертки вроде тех что вы нашли

                                                      Ну да, я понимаю, что тут стандартная концепция хромает.
                                                      Мне и за пределами плавучки, кстати, приходилось переопределять функции сравнения для особых целей. Я так понимаю, через всякие sort_by проблема решается, но об этом надо всегда помнить (и враппер типа упомянутого поможет и для других типов сравнений, если надо).
                                                        0
                                                        Если бы (гипотетически) стандарт изменил поведение сравнения с NaNs, то все что нужно было бы сделать, это добавить в стандартной библиотеке реализации типажей Eq и Ord для f32 и f64, и все алгоритмы магическим образом заработали. Это если закрывать глаза на нарушение обратной совместимости.

                                                        Только обратная совместимость никак не нарушается, ведь мы ослабляем требования, а не усиливаем. Раньше нельзя было флоаты ключами иметь, а с такой реализацией — будет можно. Юзер реализацию сломать тоже не выйдет потому что orphan rules запрещают написать такую реализацию для стандартных типов.

                                                          0
                                                          Только обратная совместимость никак не нарушается, ведь мы ослабляем требования, а не усиливаем.
                                                          Ord/Eq – публичные типажи, и могут находиться в ковариативных и контравариативных отношениях с пользовательскими типами.

                                                          Если мы ослабляем требования к типу, в случае ковариативной зависимости от этого типа обратная совместимость не нарушается. Например, следующие реализации останутся коррентными и обратно совместимыми, поскольку выполняют не меньше гарантий, чем требуется после ослабления требований:

                                                          impl Ord for Foo { ... }
                                                          impl Eq for Foo { ... }
                                                          
                                                          fn foo(...) -> Box<Ord+Eq> { ... }
                                                          

                                                          Но в случае контравариативной зависимости обратная совместимость будет нарушена:

                                                          fn foo<T: Ord+Eq>(x: T) { ... }
                                                          
                                                          impl<T> Foo for T where T: Ord+Eq { }
                                                          

                                                          Корректность функции foo и реализации Foo for T требуют больше гарантий, чем обеспечивают Ord и Eq после внесенных изменений, и потому обратная совместимость нарушается.

                                                          Более простым языком:

                                                          fn foo<T, U>(a: T) -> U

                                                          Тип foo<T, U> контравариативно зависит от своих типов-аргументов (T) и ковариативно от типа возвращаемого значения (U).

                                                          Можно ослаблять требования к типам-аргументам и усиливать требования к возвращаемому типу без нарушения обратной совместимости, но не наоборот.

                                                          Если какой-либо тип находится в ковариативных и контравариативных отношениях с другими типами (то есть используется и как аргумент, и как возвращаемый результат), то как ослабление так и усиление гарантий будет приводить к нарушению обратной совместимости. То есть такой тип является инвариантым от отношению к остальным типам.

                                                          Типажы Eq/Ord определенно инварианты по отношению ко всей кодовой базе, которая зависит от стандартной библиотеки Rust (в совокопнусти). А потому, ни ослаблять, ни усиливать их гарантии без нарушения обратной совместимости нельзя.
                                                            0

                                                            Так тут никто ничего не усиливает. Просто для одного из стандартных типов из стд добавляется трейт. Я не вижу, что это должно сломать. Вы раньше не могли использовать f64 в качестве T в T: Ord + Eq, значит от того что f64 им стал ваш код никак в семантике не изменился.


                                                            Можно привести конкретный пример кода, который должен сломаться от такой замены?

                                                              0

                                                              Ковариантность, контравариантность и инвариантность в Расте относятся только к лайфтаймам. Что-то могло бы сломаться при использовании отрицательных ограничений трейтов (T: !Eq), но в пользовательском коде они запрещены.

                                            0

                                            А ещё ненормализованные нули, которые могут заставить тормозить даже топовый компьютер.

                                              0
                                              От этого потихоньку избавляются (Intel в SSE, например, начиная с Nehalem исправляет одну ситуацию за другой). Да и изначально это было всего лишь нежеланием чуть-чуть доработать реализацию.
                                                +1

                                                Где-то я читал лонгрид по поводу этих самых ненормализованных нулей, и intel их продвинула как фичу (где-то в махровые 80ые) — мол, мы умеем считать совсем маленькие числа (меньше, чем конкуренты, которые ненормализованные нули просто игнорили или ругались).

                                                  0
                                                  Всё так. Intel вместе с Motorola. У Кахана это расписано.
                                                  Но реализация вначале была очень медленной, и только где-то после 2005 это начали исправлять.
                                              0
                                              ну раз стандарт, то всееее, нахрен логику и здравый смысл. Поздно, прокомпостировали.

                                              Где интегральные схемы, а где высокоуровневые языки, которые через 500 абстракций работают. По-моему классика легаси, единственная причина которой — стремление не думать, а просто брать что кто-то раньше «не подумал».

                                                +1
                                                Где интегральные схемы, а где высокоуровневые языки, которые через 500 абстракций работают.
                                                Между ними хоть и есть «500 абстракций», но мир гораздо теснее чем кажется.

                                                В каждом современном процессоре есть FPU, который воспроизводит поведение Intel 8087, просто потому что если он не будет этого делать, то он либо результаты работы программы будут отличаться от других процессоров (что жесть), либо придется эмулировать поведение Intel 8087 (что медленно).

                                                И когда вы на каком-нибудь высокоуровневом эсперанто вроде Python и numpy перемножаете две матрицы, несмотря на «500 абстракций» между вашим эсперанто и процессором, производительность этого добра упирается в то самое железо, которое работает так как работает.

                                                И у разработчиков языков есть два варианта – либо дать пользователю тип данных для чисел с плавающей запятой, в точности воспроизводящий поведение FPU в процессоре (пусть даже оно все кривое и косое), либо реализовать рациональные числа красиво и изящно и сразу получить просадку в производительности в 10 раз.

                                                По-моему классика легаси, единственная причина которой — стремление не думать, а просто брать что кто-то раньше «не подумал».
                                                IEEE754 был продуман очень хорошо для своего времени, и хотя там компромисс на компромиссе (читай: костыль на костыле), все это не от глупости, а от желания получить эффективную реализацию.

                                                К сожалению в hardware, в отличии от software, нельзя просто проснуться бодрым как-то утром, сесть за рабочий комп, переписать целиком кусок реализации процессора, выложить в продакшн и уйти на обед. Обратная совместимость тянется десятилетиями, просто потому что что-бы «уйти от legacy» нужно выложить на стол миллиарды долларов (вспомните Intel Itanium).
                                                +1
                                                стандарт IEEE 754, которому кое-как пытаются следовать все языки программирования.
                                                К слову, C/C++ не требуют от компилятора именно этой реализации.
                                                  +1
                                                  Они и реализацию целых чисел не конкретизируют, раз уж на то пошло.
                                                  Поэтому signed overflow — это UB.
                                                –4
                                                Браузер работает как и следовало ожидать. К чему нытьё?
                                                  +5
                                                  Браво переводчику.

                                                  Единственное, что я бы поправил:
                                                  наполненные сюрикенами и превращающиеся во львов, едва коснутся земли
                                                    +2
                                                    Вот да! Во фронтенде творится неимовернейшая хрень и никто не пытается это признать и сделать новые стандарты по уму.
                                                      +9
                                                      Проблема в том, что «стандарты по уму» окажутся тем самым пятнадцатым стандартом.

                                                      Я после прочтения статьи поразмышлял и пришёл к выводу, что это нереально. Предположим даже, что кто-то осилил написать крутейший новый стандарт, и создал под него браузер (достаточно универсальный, чтобы на него перешло большинство народу), и как-то уговорил практически всех вебсайтеров переделать сайты под этот стандарт. Уже ненаучная фантастика, но предположим. Очевидно, что в стандарте будут различные ограничения; невозможно охватить абсолютно всё. Девелоперы начнут роптать: нам надо то, нам надо это, и плевать, что оно не укладывается в рамки архитектуры и авторского видения, что оно усложняет понимание и выглядит абсурдной нашлёпкой сбоку. НАМ НАДО! И не то, чтобы я их обвиняю — стандарт пишется не для красоты, а для совместимости реализаций практических задач. Но в итоге, если автор стандарта поддастся, то мы будем иметь то же, что имеем сейчас. А если нет, то найдётся Гугл кто-то, кто скажет: возрадуйтесь, девелоперы, я сделал свой браузер, поддерживающий эту шнягу, а то, что оно вне стандарта — ну и фиг с ним, расширим стандарт своими силами. И сколько времени после этого проживёт исходный красивый и элегантный стандарт?
                                                        –1
                                                        Проблема в том, что «стандарты по уму» окажутся тем самым пятнадцатым стандартом.
                                                        Я после прочтения статьи поразмышлял и пришёл к выводу, что это нереально.

                                                        Я с вами на 99.99% согласен, но вот если в Go добавят дженерики, буду согласен на все 146%.
                                                          0
                                                          Предположим даже, что кто-то осилил написать крутейший новый стандарт, и создал под него браузер

                                                          Ну или например мы забываем про такое явление как «браузер» и ищем какой-то принципиально новый концепт.

                                                            +3
                                                            Гипертекстовый векторный фидонет? (ц)
                                                            0
                                                            Проблема 15-го стандарта в том, что нету какого-либо органа, принуждающего соблюдать стандарты. Без него сколько стандарты не принимай, они все будут иметь только рекомендательный характер.
                                                            Было бы конечно хорошо такой орган создать, но это уже совсем другая история.
                                                              +1
                                                              Тут ведь исходная мысль какая: стандарт пишется для общего удобства. Если все соблюдают стандарт, всем хорошо и радостно. Не хочешь соблюдать? Имеешь на то полное право, но тогда не удивляйся, что взаимодействие с теми, кто соблюдает, будет ограничено или вовсе невозможно. Иногда это приемлемо (для себя лично, для каких-то внутренних задач…). Разумный подход для разумных людей. Вот только, как показывает история, в массовом сегменте разумные подходы срабатывают крайне редко.

                                                              А запретиловка — палка о двух концах. Ну запретили какой-нибудь флэш, а альтернативы не предоставили. И что делать? Девелоперам плохо (HTML5 недостаточен, canvas тормозит, webgl глючит); пользователям плохо (нет любимых игрушек, чтобы просто открыл страничку и поиграл); стандартизаторам плохо (их непрестанно клюют и те, и другие)… И кто выиграл? Только те, кто видит стройный и красивый стандарт без кривого флэша. Стоило оно того? Я, например, совершенно не уверен. (Пример полностью условный, разумеется.)

                                                              Проблема явно сложнее и не решается подходом «да взять всё и поделить».
                                                              +1

                                                              Недавно же был статья про то сколько стандартов w3c выходит в год, откуда следовало, что сделать новый браузер по таким стандартам уже невозможно физически, никому.

                                                            +2
                                                            К сожалению, на мой непрофессиональный взгляд, сказанное тут про браузеры правда. Браузеры усложняются, добавляется куча «крутых, модных» фич, и с очередным обновлением веб браузер жрёт всё больше памяти. Браузерные движки уже невозможно нормально обслуживать, из за количества кода, а вероятность появления нового браузерного движка стремится к нулю со скоростью света создания копий браузера google chrome, только с изменением цвета фона.
                                                              0
                                                              На момент появления Google Chrome тоже все говорили, что «вероятность появления нового браузерного движка стремится к нулю со скоростью света создания копий браузера mozilla, только с изменением цвета фона.»
                                                                +3
                                                                Так нового и не было, KHTML появился где-то в районе Gecko. Вопрос конечно, что от него осталось, но в целом корни то оттуда
                                                              +6
                                                              Мазафака. Этот негр воображает себя Львом Толстым. Дальше фраза из Льва Толстого для сравнения
                                                              Стоя в холодке вновь покрытой риги с необсыпавшимся еще пахучим листом лещинового решетника, прижатого к облупленным свежим осиновым слегам соломенной крыши, Левин глядел то сквозь открытые ворота, в которых толклась и играла сухая и горькая пыль молотьбы, на освещенную горячим солнцем траву гумна и свежую солому, только что вынесенную из сарая, то на пестроголовых белогрудых ласточек, с присвистом влетавших под крышу и, трепля крыльями, останавливавшихся в просветах ворот, то на народ, копошившийся в темной и пыльной риге, и думал странные мысли.
                                                                +5

                                                                Что происходит? Неделю не выходит новый JS фреймворк и все решили его поносить?


                                                                Статья конечно веселая, но на практике от половины описанного спасает простой eslint.


                                                                Number.prototype.valueOf = function(){return 42;};

                                                                ужас да какой, каждый день с такой проблемой сталкиваюсь, никак не могу перестать переопределять глобальные классы и использовать прототипы.


                                                                Кроме того, JavaScript определяет два оператора тождественности (=== и !==), не выполняющих приведения типов, выполняемого стандартными операторами равенства; однако, NaN !== NaN.

                                                                Да, учил разницу между == и === несколько лет, а NaN вообще магия. Не понимаю, как что-то, может быть не числом


                                                                Хоть каждое предложение нарезай и угарай поверх его мыслей

                                                                  +1

                                                                  Никоим образом не относясь непосредственно к разработке фронта, мне таки приходится периодически его деплоить и немножко суппортить. И примерно раз в полгода вспоминается мне вот этот доклад в частности: https://events.yandex.ru/events/yac/2013?openTalkVideo=252-37

                                                                    +7

                                                                    Помню, как со мной случилась истерика, когда со всего размаху охреначился об то, что в JS первый месяц — это февраль.

                                                                      +4
                                                                      Удивили. Неужели вы с Date столкнулись до того, как познакомились с массивами, например? Уж больно типична нумерация с нуля, на моей памяти, кажется, элементы массива с единицы считали только в некоторых бейсиках, фортране и паскале (ну, там явно диапазон указывался).
                                                                        +7
                                                                        • Месяцы не подразумевают массивы, где можно было бы ожидать такое поведение
                                                                        • У дней месяца такой проблемы почему-то нет
                                                                        • У конструктора есть форма с параметром строкой, где такой проблемы тоже нет.
                                                                          +3
                                                                          В целом соглашусь, но зная, что массивы начинаются с 0 – не воспринимаешь нумерацию месяцев с 1 как единственно возможную.
                                                                          Т.е. считать нумерацию месяцев с нуля неудобной я могу (хотя и маленькие плюсы в ней есть), а вот удивляться ей – нет, и заглянуть в документацию, чтобы выяснить, как нумеруются месяцы, для меня естественно.
                                                                            +2
                                                                            Удивление вызывает необоснованность и локальность такого решения. Искать подобные подвохи в документации — это противоестественно.
                                                                              +2
                                                                              А у кого-то вызывает удивление использование где бы то ни было нумерации с единицы: она же не ложится на массивы. Скажем, массив названий месяцев на государственном тундрюкском языке, или количества родившихся в каждом месяце. И он считает необоснованной нумерацию с единицы.

                                                                              Так что если у вас нет рефлекса подмечать такие опасные места (где одному покажется естественным одно, а другому другое) и кажется противоестественным лезть в этом случае в документацию – вам тяжело.
                                                                                –1
                                                                                Это не вкусовщина, чтобы делиться на «нравится»/«не нравится». Если у такого неконсистентного решения нет практической выгоды, то оно необосновано.
                                                                                  +1
                                                                                  Вы про нумерацию потенциальных индексов массива с единицы? ;-)
                                                                                    –1
                                                                                    Это тоже, кстати, не более, чем дань привычке в таком высокоуровневом языке, как JS. Но я допускаю, что изменение этого ожидаемого поведения может приводить к ошибкам. А с Date у JS свое персональное «хау-ноу».
                                                                                +4
                                                                                Можно легко предположить что автору хотелось вот такого:
                                                                                const monthNames = ['Январь', 'Февраль', ...]
                                                                                months.map(n => monthNames[n])
                                                                                

                                                                                Я больше одного раза видел в чужом коде (по-моему в пхп) месяц Нулябрь в начале массива, потому что нумерация месяцев с 1, а нумерация массивов с нуля, а жизнь — борьба.

                                                                                Алсо если бы нумерация начиналась с 1, то кто-то другой (или даже вы сами) написали бы точно такой же комментарий, про удивление, необоснованность и противоестественность. Потому что всем не угодишь.
                                                                                  +2
                                                                                  месяц Нулябрь

                                                                                  Это великолепно!
                                                                                    0

                                                                                    Это баян классика :)

                                                                                      +3

                                                                                      Рискуя быть занудой:


                                                                                      $months = [1 => 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'];
                                                                                        0

                                                                                        Только надо учитывать, что это ассоциативный хэш, а не массив, и поэтому доступ по индексу выполняется в несколько раз медленнее.

                                                                                          +3
                                                                                          Код выше подозрительно похож на PHP, и что-то мне подсказывает, что там разницы не будет.
                                                                                            +2
                                                                                            Только надо учитывать, что это ассоциативный хэш, а не массив, и поэтому доступ по индексу выполняется в несколько раз медленнее.

                                                                                            Чем где? В PHP любой массив всегда ассоциативный, что ты с ним ни делай.
                                                                                            Впрочем, они их хорошо оптимизировали, потому производительность – далеко не главная проблема такого архитектурного решения.

                                                                                            0
                                                                                            Вы ничем не рискуете: я застал переход с пхп 4 на пхп 5, до появления такого синтаксиса оставалось меньше 10 лет…
                                                                                              0
                                                                                              Вы ничем не рискуете: я застал переход с пхп 4 на пхп 5, до появления такого синтаксиса оставалось меньше 10 лет…

                                                                                              Да, квадратные скобки как замена array() появились в PHP 5.4, но вовсе не в этом суть.
                                                                                              Ну хорошо, вот, это будет работать хоть на PHP 4:


                                                                                              $months = array(1 => 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь');
                                                                                        0

                                                                                        Я это увидел на башорге.


                                                                                        В коде не встречал, т.к. в Java есть логичные enum-ы, а в javascript стараюсь не заглядывать — не люблю я его.

                                                                                        –1
                                                                                        del
                                                                                        Это наркомания какая-то)
                                                                                  +1

                                                                                  Выяснил, что этот идиотизм с нулевым месяцем пришёл из большой Джавы. Господи, каждый раз тихо за себя радуюсь, что удалось в неё не вляпаться.

                                                                                    +1

                                                                                    Да ладно, месяцы с нуля или с единицы – это как думать, бороду во сне на одеяло класть или под одеяло. Так и так неудобно.

                                                                                      0

                                                                                      Если у меня есть дата, к примеру, 17.03.2020, то в конструктор new Date(year, month, day) я должен передавать числа 2020, 3 и 17. Других чисел у меня нет. По крайней мере, я в упор не вижу.
                                                                                      Всё остальное ненормально. Всё остальное или шизофрения, или психопатическое желание поиздеваться над джунами.

                                                                                        +1
                                                                                        Вот бы сейчас задумываться, какой там номер у месяца…

                                                                                        Если это константы в коде, то используйте библиотечные константы.
                                                                                        Если оно пришло вам в виде строки, то парсьте не руками, а специальным библиотечным парсером, который умеет правильно парсить.
                                                                                        Если вам надо из даты(объекта) собрать такую строку, используйте специальный библиотечный форматтер, который умеет правильно форматировать.
                                                                                        Если оно пришло вам в таком виде(год месяц число) извне отдельно — страдайте используйте java.time.Month.of.
                                                                                      +1
                                                                                      > Выяснил, что этот идиотизм с нулевым месяцем пришёл из большой Джавы.

                                                                                      Он появился в изначальном Unix. А вот почему дальше его копируют 1:1 — вопрос интересный :)

                                                                                      > Господи, каждый раз тихо за себя радуюсь, что удалось в неё не вляпаться.

                                                                                      У вас Python? Там зачем-то сдвинули отсчёт даже в одноимённой структуре :)
                                                                                      А на Java вы зря бочку катите, вот остановится развитие по Муру — сначала начнут дохнуть все чисто динамические языки.
                                                                                        0
                                                                                        Он появился в изначальном Unix. А вот почему дальше его копируют 1:1 — вопрос интересный :)

                                                                                        Здесь просто напрашивается басня про шатл и лошадиную задницу.

                                                                                        Можно ещё вспомнить, что в VBA коды ошибок унаследованы — через длинную вереницу бейсиков — из Microsoft BASIC-80; поэтому их нумерация начинается с 3 и идёт с пропусками.
                                                                                  +1

                                                                                  Если бы автор разрабатывал во времена IE6, он бы знал, что сейчас — рай.

                                                                                    0
                                                                                    Во времена IE6 сайты были намного проще по функционалу.
                                                                                      0
                                                                                      Во времена IE6 поддержки одного IE6 было достаточно для 95% аудитории.
                                                                                      Сложности начались, когда появился зоопарк разных браузеров.
                                                                                        +2
                                                                                        Зато сейчас, блин, никаких сложностей. Сколько ни сообщал о багах работы сайтов в Firefox, ни разу нигде не поправляли.
                                                                                      +3
                                                                                      Самая сильная часть в этом рассказе про экоактивиста, который столкнулся с суровой реальностью. :-)
                                                                                        +1
                                                                                        Шедеврально. Можно растаскивать на цитаты
                                                                                          +9

                                                                                          Уже второй раз за день комменчу свое непонимание комментами.
                                                                                          Автор же явно стебется, и у него явно огромный опыт работы с вебом и тем более отличное его понимание. Он в качестве альтернативы предлагает вам использовать сигналы, передаваемые зеркалами. Ну серьезно, народ, вам предлагают отказаться от браузеров в пользу зеркал, а вы придумываете аргументы, почему он не прав?

                                                                                            0
                                                                                            В качестве альтернативы он предлагает написать новый веб с нуля. И, да, это смешно.
                                                                                              +2
                                                                                              Э… Где? Я был невнимателен или это в других статьях того же автора?
                                                                                                +1
                                                                                                В заголовке и последнем слове. Всё по канону.
                                                                                                +2
                                                                                                ну, с нуля не с нуля, но олдскульный треш должен как-то уходить.
                                                                                                  0
                                                                                                  Ну вот, например, ФФ бодрее выпиливает deprecated, а люди продолжают так писать, ведь самый массовый браузер поддерживает.
                                                                                                    0
                                                                                                    Если ФФ неправильно показывает мой любимый сайт, то что я сделаю?
                                                                                                    а) убедю хозяев сайта его переписать; или
                                                                                                    б) выкину ФФ и поставлю браузер, который показывает мой любимый сайт правильно?
                                                                                                      0
                                                                                                      Б. Вариант Б. Это значит, что браузерам для успешности нужно тащить как можно больше легаси. Пока не останется только один, владельцы которого всех заставит ходить через свои сервера, и (не обязательно, но возможно) писать сайты как они скажут и на чём скажут. По крайней мере, так им мечтается.
                                                                                                        0
                                                                                                        Вот и sumanai пишет в ветке выше: «Сколько ни сообщал о багах работы сайтов в Firefox, ни разу нигде не поправляли.»
                                                                                              +1
                                                                                              «Чем ты ближе к земле, тем ближе к тебе черви».
                                                                                                +1
                                                                                                интересная статья, спасибо за перевод!
                                                                                                  0
                                                                                                  После прочтения включил везде «use Strict» > Исправил все баги в Chrome > Проверил другие браузеры > Выключил «use Strict» от греха подальше…

                                                                                                  Сдается мне, что JavaScript повторит судьбу Visual Basic и будет вытеснен другими языками (Dart, TypeScript, Kotlin и прочими), которые в будущем тоже будут нативно поддерживаться браузерами. И в один прекрасный солнечный день JavaScript отключат как отключили Flash. И причиной как и тогда будет security.
                                                                                                    +1
                                                                                                    У того, что Microsoft прекратила развивать Visual Basic, не было никаких объективных/технологических причин.
                                                                                                    Просто сменилась мода снаружи MS и вкусы руководителей внутри MS.
                                                                                                      +2
                                                                                                      Да, во многом вы правы, дело тут не совсем в технологии.

                                                                                                      VB (как и JS) был достаточно легок в использовании, что привело к тому, что его стали применять большое количество людей далеких от программирования. Офисные сотрудники, новички и студенты пилили свои программы и скрипты и повсюду развешивали спагетти-код. А VB не делал ничего, чтобы помешать укоренению их плохих привычек. Это привело к падению репутации языка и его медленному угасанию.

                                                                                                      Те же самые симптомы, к сожалению, наблюдаются у JavaScript — на нем слишком легко писать плохой код и это сильно бьет по его репутации.
                                                                                                        0
                                                                                                        Так VB был создан как раз для того, чтобы домохозяйка могла налабать себе скриптец в Excel.
                                                                                                          +1
                                                                                                          Офисные макросы — это VBA (Visual Basic for Applications). А на самом VB лабалось немало прикладного софта под винды в свое время.
                                                                                                            0
                                                                                                            В «отдельном» VB по сравнению с VBA только добавлялся компилятор, и заменялась стандартная GUI-библиотека. Сам язык при этом был один и тот же.
                                                                                                              0
                                                                                                              Цель создания разная. VBA — это не весь VB.
                                                                                                    +2
                                                                                                    Хотелось бы добавить, что я нисколько не принижаю JS как язык, он в чем-то прекрасен и дает большую свободу. Но это его достоинство в не очень умелых руках среднестатистических кодеров приводит к созданию тяжелоподдерживаемого и глючного кода. Я встречал много талантливых людей которые пишут на JS прекрасный чистый код, но, к сожалению он тонет в тоннах спагетти кода, созданного большинством, что серьезно бьет по его репутации.

                                                                                                    JS прекрасен для творчества, но плох для бизнеса из-за неоправданно высокой стоимости дальнейшей долгосрочной поддержки продуктов.
                                                                                                      +3
                                                                                                      Назовите какой-нибудь язык, который даже в не очень умелых руках среднестатистических кодеров приводил бы к созданию легкоподдерживаемого и безглючного кода?
                                                                                                        +2
                                                                                                        Языки со строгой типизацией — в них сложнее выстрелить себе в ногу.

                                                                                                        Языки со слабой типизацией весьма хороши для быстрого создания прототипов, MVP и небольших проектов — на них всё можно сделать все очень быстро. Но когда проект разростается до сотен тысяч и миллионов строк когда, вероятность ошибок растет геометрически.

                                                                                                        Обьем кода на веб страницах сейчас быстро растет и слабая типизация уже не лучший вариант. Откройте консоль при работе на сайтах банков — ситуация, как заметил автор, весьма и весьма печальна — она очень сложно контролируемая, что уж говорить про большинство сайтов.
                                                                                                          0
                                                                                                          C++ — язык с достаточно строгой типизацией?
                                                                                                            +7
                                                                                                            С++ это язык со слабой типизацией и в больших проектах это тоже источник большого количества сложно-уловимых ошибок. Но в отличии от JavaScript там больше опытных разработчиков, которые выработали свои определенные правила кодирования, некий безопасный подъязык. Но и это не особо помогает и идет постепенная миграция в сторону Rust.

                                                                                                            Языки с достаточно строгой типизацией это Java, Kotlin, C# (TypeScript вроде как тоже). Если мы говорим про банковский сектор и кровавый интерпрайз — это в основном Java. Причем уровень разработчиков даже в банках мирового уровня весьма и весьма посредственный, но типобезопасность наряду с TDD дает приемлемое качество, маштибируемость и довольно низкую стоимостью поддержки.

                                                                                                            У JavaScript довольно низкая стоимостью первоначальной разработки, но проблемы с маштабируемостью и стоимостью дальнейшей поддержки.

                                                                                                              +2

                                                                                                              Нет.


                                                                                                              И кроме слабой типизации (которая скорее приводит к логическим ошибкам) там заботливо расставлена куча мин и ловушек в виде UB.

                                                                                                              +1

                                                                                                              Со строгой статической тогда уж.

                                                                                                          –1
                                                                                                          Разве сейчас с помощью WebAssemly нельзя писать код в вебе на практически любом языке?
                                                                                                            0
                                                                                                            WebAssembly пока что c DOM и WebAPI работает через ту же JS-прослойку (это и медленнее, и требует некоторых танцев, либо генерацию кучи boilerplate-кода).
                                                                                                            Плюс обеспечивает только базовый рантайм, то есть все библиотеки компилятся в тот же самый бинарь, который каждый раз скачивается и компилируется (то есть нет такого, чтобы как с JS-фреймворками, закинул либу на CDN и не плодишь сущностей).
                                                                                                            И в ту и в ту сторону были планы по решению этих проблем (возможно уже даже есть подвижки в этом направлении, давно не заглядывал в спеки), но прямо сегодня писать фронтенд на WASM — все-таки экзотика.
                                                                                                              0
                                                                                                              который каждый раз скачивается и компилируется

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

                                                                                                                  Ну или Mono, который пусть и вестит тонну (пока встроенный GC в WASM не завезли), но агрессивно кэшируется и абстрагирует системный ABI, позволяя исполнять .NET-сборки без оглядки на него.
                                                                                                          +2
                                                                                                          Боже, самая уродливая статья, что я здесь когда-либо читал. Попытки автора оригинала постоянно шутить и нон-стопом приводить абсолютно не уместные сравнения/аллегории/etc просто нереально(использую здесь модное, но чертовски актуальное словечко) «душат». И если весь этот балаган и камеди-клаб отбросить, то от статьи останется очередное, ничем не отличающееся от других, нытье про несовершенство текущего веба. Ну и куда же без тычка в сторону JS? А тот момент, где автор намеренно изменяет поведение прототипа объекта, а потом жалуется, что все работает не так и винит во всем JS — просто шедевр.
                                                                                                            +2
                                                                                                            В оригинале это всё реально смешно! Отличная стёбная статья, вы чего, люди?
                                                                                                            –3
                                                                                                            «Quirks mode» это не «Вычурный режим». Лучше «Режим совместимости» или не переводить вообще.
                                                                                                              +3
                                                                                                              Приложеньице запущено.
                                                                                                              0

                                                                                                              TL;DR о чем речь — можно резюмешку плиз ?

                                                                                                                +3
                                                                                                                Всё очень плохо в современном вебе и его пора смыть в унитаз.
                                                                                                                  +1

                                                                                                                  Спасибо. Можно было не писать — это и так очевидно (в смысле не про ваш коммент, а про статью) )

                                                                                                                +1
                                                                                                                Классный перевод и чтиво на ночь :))) Спасибо!

                                                                                                                Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                                                Самое читаемое