Pull to refresh

Comments 67

Вертикальные надписи неудобны, если нельзя сделать горизонтальные, то хотя бы поворот в другую сторону сделать.
Глядя на эти таблицы, возникает непреодолимое желание запустить жизнь Конвея на них.
Класс! Спасибо!
Три планера улетели вроде бы.
первые две таблица (особенно вторая) весьма симметричны относительно диагонали. По мне это удобнее для запоминания нежели треугольник под диагональю.
Для запоминания? Это кто-то может помнить?
Ну а для чего тогда еще нужна симметрия таких данных?)
Я не знаю для чего. Надо просто понять как это работает, а не запоминать какими-то страшными таблицами.
Не надо понимать, как это работает. Надо просто везде использовать ===, а за == бить по рукам линейкой во время code review.
Ну да, давайте вообще перейдём на строгую типизацию и всё. Я не против использовать три равно там, где это уместно — именно для сравнений без приведения типа. Два равно нормальная, логичная операция, если рисовать устрашающие таблицы, конечно будет казаться, что всё ужасно, тогда как эта операция работает по вполне нормальным, логичным принципам, ничего страшного в ней нет.
Нет ничего плохого в динамической типизации — проблема в приведении типов. Не было бы автоматического приведения типов, не было бы проблем.
Да нет ничего плохого в приведении типов. Хорошая вещь, позволяет быстро писать. Уметь пользоваться надо просто.
Понимаете, когда ноль равен пустому списку — это не «нормальный, логичный принцип».

И, да, строгая типизация (подчеркиваю — строгая, а не статическая — т.е. без неявных преобразований) — это хорошо. Лучше лишний раз написать явное приведение, чем пытаться судорожно вспомнить, что к чему приведется в данном конкретном случае. Тут есть исключения, вроде int->double (в тех языках, где есть и то, и другое), но в целом неявные преобразования позволяют экономить от силы по десятку символов на функцию, при этом внося хитрые и труднообнаруживаемые баги.
Ноль равен пустому списку не просто так, есть причина. У этого сравнения есть логика, её просто знать надо и проблем не будет тогда. И у строгой и у статической типизации есть плюсы.
Хорошо, переформулируем. У этого сравнения есть логика (очень неочевидная, правда), но у него нет ни капли здравого смысла.
UFO just landed and posted this here
Ну и, кстати, если программируешь на языке, обязан понимать как у него что работает.
Если язык грамотно задизайнен — то да. Но есть языки с изначально кривым дизайном, да и в нормальных со временем накапливается legacy-мусор, который изучать не имеет никакого смысла — проще просто пользоваться новыми средствами. Например, программисту на C# сегодня не нужно изучать синтаксис анонимных делегатов — лямбды делают то же самое лучше и короче. Программисту на Питоне (2.x) вряд ли имеет смысл разбираться с old-style классами. И так далее.
Не спорю, JS плохо задизайнен. Но что не так с ==?
То, что мы обсуждаем в этой ветке — неявные преобразования не по делу. Для равенства вида 0==[] нет никакой практической пользы. Ну никогда вы не напишете код, где это будет использоваться. А вот случайно наступить на грабли это позволяет. Это — однозначно плохой дизайн.
А в каких языках, где есть эта операция, это решается как-то удачнее?
Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 0 == []
False
>>> 0 + []
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'list'

т.е. false в этом случае почему-то удачнее true?
Да, удачнее. Два объекта разных типов никогда не равны — все просто и понятно.

(Справедливости ради, в Питоне таки можно сравнить 42.0==42, и это даже даст True, хотя типы разные — но «логический» тип тут одинаковый: число)
Ноль в JS не объект, справедливости ради.

Выше вы мне писали, что операция 0==[] вредна, потому что не имеет практической пользы и способна породить ошибки. И тут же вы приводите её же в Пайтоне, но оказывается, что тут она чем-то полезна и ошибки породить не может.

И, кстати, ничего не стоит сделать в Пайтоне объект, который будет равняться чему угодно.
Я не писал, что операция 0==[] вредна. Я писал, что результат true из этой операции никогда не имеет практической пользы. А вот false как раз вполне имеет, по описанным выше причинам.

Кстати, это специфика не только Питона. В том же C# или Java тоже есть Object.Equals с точно такой же семантикой — два объекта разных типов (обычно) не равны.

Да, разумеется, поскольку == в Питоне является перегружаемым оператором, то ему можно присвоить какую угодно семантику, как и в любом другом языке с перегрузкой. Но речь здесь идет о 1) поведении стандартных типов, и 2) принятых соглашениях по написанию кастомного сравнения.
Ну так докажите, что [] == 0 с результатом true плохо, а с false хорошо. Я что-то не увидел никакой разницы. Ясно же, что в жизни именно так никто не проверяет. Встретится что-то вроде a==b или a==[], а true там или false вернётся — неважно. Нежелательная логика может быть по любой из веток.
В жизни сплошь и рядом проверяют параметры функций. Что-то вроде такого:
READ = 0
WRITE = 1
def open(name, mode = READ):
  if mode == READ:
    ...
  elif mode == WRITE:
    ...
  else:
    raise ValueError

Если у нас []==0, то можно неочевидным образом вызвать эту функцию как open('foo', []). Если []==0 дает false, то вызов с [] (и любым другим некорректным типом) сразу же даст ошибку.
Во-первых, константы у вас странные. Что вам мешало сделать READ, WRITE = object(), object()? Какой смысл на Пайтоне как на Си программировать?

Ну так можно подобрать код, в котором в случае true что-то случится ненужное. Разве нет? Тут вам повезло, причём не из-за дизайна языка, а из-за случайности. А в другой раз может не повезти.
Я сходу не могу придумать ситуации, где от проверки ([]==0)==False случится «что-то ненужное».

На самом деле тут имхо причина очень простая — дело не в результате сравнения, а в его логике. Вариант с True включает в себя совершенно неочевидные неявные преобразования, вариант с False — не включает. Значит, последний проще и предсказуемее, а значит — код будет понятнее, а багов будет меньше.

Если же преобразования есть, то надо думать, какой из двух (или более) логичных вариантов там начинает работать. Т.е. скажем, для 1==«1.0», приводится строка к числу, или число к строке? Какой бы вариант не предпочитать, возникает вопрос: а почему именно он? По сути, если у двух значений разные типы — а ведь тип определяет поведение — то непонятно, какое поведение должно превалировать. Здравым смыслом это не описывается, это из разряда «просто надо запомнить». А вот «объекты разных типов никогда не равны» — это вполне интуитивно понятная вещь.

Да, еще хуже, что с преобразованиями сравнение перестает быть транзитивным — «1»==1, и 1==«1.0», но «1»!=«1.0».
Так уж получилось, что все что с точки зрения людей не интуитивно понятно — плохо.
Вот и вся логика.
Поэтому лишь голосование может выявить то, что 0==[] не хорошо.
Почему то я в результате не сомневаюсь.
Попробую немного расширить ответ.

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

И, да, это все касается только == и !=. Любое другое сравнение дает ошибку, поскольку нет осмысленного способа его задать:
>>> 0 > []
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: int() > list()

Это в третьем Пайтоне выдаст ошибку. Попробуйте посравнивать объекты встроенных типов во втором и понять логику. Я, если бы не знал, так и не догадался бы.
Т.е. Гвидо это расценил как ошибку дизайна языка — и исправил в новой версии, где обратная совместимость не имеет принципиального значения. QED.
Причём тут QED? Мы больше/меньше стороной затронули, говорит о равенстве.
Да во всех нормальных языках (может быть, кроме php) такая операция выкинет исключение. Всё, на грабли наступить сложно: вместо странного некорректного результата — аварийное завершение или корректная обработка (в зависимости от того, перехватили исключение или нет).
Такая операция не выкинет ислючение в Пайтоне, Перле, ПХП, JS. Думаю, в Руби не выкинет (не уверен, я его не знаю, но он делался под большим влиянием Перла).

О каких языках речь вообще?
Как это нет никакой пользы? А как же вот такие ништячки:
a || default
if (a) {
callback && callback()
!!a
str = num + ""
Для того, чтобы работали первые три строки, достаточно определить «false value» для разных типов. Необязательно вводить при этом какие-то неявные преобразования, и уж тем более приводить обе стороны к boolean. Для примера, посмотрите на плюсовый explicit operator bool, или на operator true и operator false в С#.

!!a — на это многие как раз ругаются, поскольку это, мягко говоря, не очевидный способ приведения к boolean. Все-таки для таких штук лучше явно написать сравнение.

Автопреобразование всего, что попало, в строки при конкатенации — это часто встречаемая фича. Я все же предпочитаю питоновский подход, где это не определено, и приведение нужно делать явно, потому что неочевидно, что должно делать выражение вида 1+«2». Есть языки, в которых это решено введением отдельного оператора конкатенации — напр. в Lua, 1+«2» даст 3, а вот 1..«2» даст «12» — тоже вариант.
Вы используете русский язык, но позволяете себе допускать ошибки. В ту же секунду, Вы обязываете использовать язык только если «понимаете» как он устроен. Как это звучит?
Во-первых, вы путаете два омонима. Речь не идёт о натуральных языках. У меня во рту тоже язык, обсудим и его?
Во-вторых, из «обязан понимать как работает» не следует «не делать ошибок». Я знаю как работает JS, но ошибки делаю. Просто не те причина которых непонимание как работает.
Больше на ПМС похоже: оспаривается только самая первая претензия, причём безо всяких аргументов.
В чужие проекты со своим codestyle не ходят
Они симметричны, потому что порядок значений по обоим шкалам одинаков и исследуемая операция коммутативна.
== — коммутативная бинарная операция, которая принимает на вход два операнда и её результатом является некоторое булево значение, «истина» если операнды считаются равными или «ложь», если не считаются.

то, что в основе её лежит отношение, это правда. Но она не является отношением. Кстати, она нарушает это отношение, она не транзитивна в джаваскрипте: 0==«0», "" == 0 но «0» != "".
Похоже вы правы насчет отношения vs операция.

Однако я не совсем понял, замечания:
Кстати, она нарушает это отношение, она не транзитивна в джаваскрипте: 0==«0», "" == 0 но «0» != "".


Отношение может быть симетричным, но не обязано быть транзитивным.
Я неправильно выразился. Хотел сказать, что эта операция выражает не отношение «равно», которое транзитивно, а особое отношение языка Javascript, которое похоже на «равно», но не совсем, поскольку не транзитивно.
Кошмар, товарищи!.. Как по мне, так здесь бóльший беспорядок в очерёдности строк/столбцов.

Сгруппировав их по наличию пересечений мы получим более внятную картину:

Вот-вот, «если сгруппировать»… А группировать надо не по количеству пересечений таблицы, а по классам операндов. Как на первой, «некрасивой» картинке.
Ох, такое ощущение что тут собрались наркоманы! Сходите уже прочтите спецификацию!!! Сложно? ну тогда у вас все уныло
В спецификации достаточно запомнить 4-5 правил после чего вы сами сможее вывести эту таблицу, но нет, проще наверное заучить 441 ячейку бреда
231 ячейку, тут сравнение коммутативно :)
по моему надо просто всем дружно сказать «хватит писать на js»
не пишите, вас заставляют?
и на чем тогда писать?
Не надо. Это просто маразматическая и ненужная таблица. Нужно понимать правила преобразования типов, а учить эту тупизну.
А что мне делать, если мне нравится этот язык? :(
По-моему надо безудержно, неумолимо переставать говорить за всех.
А разве нет? Разве у меня есть выбор на чём писать Web приложения?
DartJS / CoffeeScript / TypeScript?
Конечно с последующей компиляцией в JS, но тем не менее в этих трансляторах есть свои реализации равенств.
Опипишитесь в чем я не прав?
Да в принципе вы правы. Я имел ввиду что нам всем нужно отказываться от js в пользу языков компилирующихся в js, с той целью чтоб производители браузеров(в частности google) могли опираясь имеющиеся тенденции добавить dart(например) в качестве скриптового языка по умолчанию в браузере.
UFO just landed and posted this here
Sign up to leave a comment.

Articles