Pull to refresh

Comments 9

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

Зачем "намертво" выбирать конкретную деталь реализации, если стандарт языка (например, в случае C++) этого не требует?

Почему не реализовывать наиболее оптимальным в каждой конкретной ситуации образом?

Какой вообще плюс в "выборе намертво - чтобы обязательно через таблицу переходов"?

Формально автор прав, switch не эквивалентен набору if-else, а значит не является синтаксическим сахаром вокруг If. Фактически и Вы правы, ничего не мешает современным компиляторам развернуть и цепочку if-else через таблицу переходов (которая далеко не во всех случаях вообще будет быстрее), а значит и разница не так велика.

А я вот вспомню, что операторы break в ветках switch в наборе языков (как минимум на базе C) опциональны, и хоть чаще это создаёт проблемы из-за забытого break, иногда это используется для полезного, например техники loop unrolling и вот это вот принципиально не эквивалентно If-else цепочкам.

А меня вот бесит то что break автоматом есть в swift в switch. Может мне надо выполнить 2 case’а в определенных условиях. И вот это мне наоборот не нравится

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

Выбор конкретного механизма воплощения в машинный код - задача оптимизирующего компилятора. Может быть он вообще предпочтёт какой-то if или switch выоптимизировать к чертям собачьим.

Задача спецификации языка - описать как меняется наблюдаемое состояние. Соответственно, если мы говорим про ситуацию, когда у нас есть пример с эквивалентными друг другу if и switch конструкциями - зочем спецификации языка вообще различать их?

Формулировка "Должен быть реализован через таблицу и никак иначе" - по моему, не несёт абсолютно никакой пользы, но связывает руки компилятору.

Но и от своего твёрдого убеждения, что реализовывать данную синтаксическую конструкцию нельзя ни как иначе, нежели при помощи таблицы переходов, не отступаю!

Для реализации таблицей переходов следущего switch-a

switch (x) {
        case 1014593462573: //...
        case 5: //...
        case 1113567: //...
}

потребуется таблица из 1014593462569 элементов. Это точно не перебор?

Современная Java, например, хитрее (сужу по smali-коду для android) : в зависимости от набора значений в case-ах, порождает 3 разных варианта кода: тривиальный код на сравнениях, либо табличный переход за O(1), либо двоичный поиск в отсортированной компилятором таблице "ключ -> метка" за O(log(N)) в случае, если таблица переходов оказывается слишком разрежённой.

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

https://stackoverflow.com/questions/60109992/why-is-a-switch-not-optimized-the-same-way-as-chained-if-else-in-c-c – 5 лет назад MSVC и CLang благополучно оптимизировали цепочки if-else.

А нежелание использовать switch-case скорей обусловлено его недоработанностью (где типы, отличные от целочисленных? где интервалы?) в C. Плюс поверх ещё место для ошибок при проваливании из кейса в кейс (благо, в C++ в конце концов сделали [[fallthrough]]). Ну, зато на нём Duff's device можно собрать :-)

Выглядит так, что вы доказали, что ваши оппоненты правы - это действительно сахар.

Таблица переходов будет оптимальной только при определенной структуре значений данных. Разреженные данные все равно приведут к неэффективным сценарием сравнения с частью вариантов.

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

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

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

Так что да, кажется и в том, что это не важные детали реализации критики тоже правы.

Надо сказать, что на хардварном уровне любое обращение к адресу строится на двоичных переходах.

Это сахар по нескольким причинам.

Во-первых, нельзя нагенерить switch-case с помощью C++ шаблонов, а вот эквивалентный if очень даже можно. Поэтому компилятор обязан уметь превращать такой if в switch-case, чтобы "шаблонизация" кода не приводила к "штрафу".

Во-вторых, в промежуточном представлении нет ни if ни switch-case, а только линейные блоки с условными и безусловными переходами между ними и эквивалентные if и switch-case дают одинаковую структуру блоков, которая дальше обрабатывается одинаково.

Sign up to leave a comment.

Articles