Переключатель
Переключатель можно считать разновидностью условного выражения,
которая в некоторых случаях удобнее обычного условного выражения.
Чем они отличаются?
-
В переключателе проверяется только один объект, который сопоставляется с чем-то другим.
-
Производится проверка этого объекта на равенство (только равенство!) ещё какому-то объекту.
-
После заголовка переключателя перечисляются возможные значения, которые может принимать объект.
Т.е. переключатель — это условный оператор, который «специализируется» на проверке одного единственного объекта
(и только его) на равенство (и только равенство) некоторому набору значений.
Исключать его из арсенала инструментов будущего языка программирования не стоит.
Оператор «switch» в C/C++ выглядит примерно так:
switch (проверяемый на равенство объект)
{ case вариант значения 1:
операторы
break;
case вариант значения 2:
операторы
break;
case вариант значения 3:
case вариант значения 4:
операторы
break;
default:
операторы
}
Преписываем в своём скобочном стиле:
(switch проверяемый на равенство объект
case вариант значения 1
операторы
case вариант значения 2
операторы
case {вариант значения 3, вариант значения 4} // не одно значение, а множество
операторы
default
операторы)
IDE нарисует тот синтаксический сахар, который мы старательно удалили.
Внимательные читатели могут заметить, что код на Си может быть таким:
switch (проверяемый на равенство объект)
{ case вариант значения 1:
операторы
case вариант значения 2:
операторы
break;
case вариант значения 3:
операторы
}
Мы видим, что оператор «break» может отсутствать между ветвями «case».
Т.е. после выполнения одной ветви «case» выполняется идущая ниже.
Ничего хорошего в этом нет.
Это провоцирует появление «спагетти-кода».
Такую возможность следует исключить так же безжалостно, как и в случае с «goto».
Поэтому одна ветвь «case» должна заканчиваться, когда начинается следующая.
А теперь подводим итог, изобразив наши идеи в «симметричном скобочном» стиле.
(
|
switch проверяемый на равенство объект
|
|
|
|
case вариант значения 1
|
|
|
операторы
|
|
|
case вариант значения 2
|
|
|
операторы
|
|
|
case { вариант значения 3, вариант значения 4 }
|
|
|
операторы
|
|
|
|
|
default // Может «default» заменить на «else»? Экономия...
|
|
|
операторы для всех остальных случаев
|
)
|
Опубликовано: 2013.05.04, последняя правка: 2014.12.20 10:48
Отзывы
✅ 2014/12/22 13:20, Сергей #0
А как бы выбиратель (переключатель) выглядел бы с русскими служебными словами?✅ 2014/12/23 03:32, Автор сайта #1
В языке «Эль-76» в этом случае писали «выбор» — «из».✅ 2015/04/10 02:01, misha_shar53 #2
Синтаксис переключателя взят от Си, а содержание от Паскаль. Это сбивает с толку. Надо тогда и синтаксис брать Паскаля. Он, по-моему, более лаконичный. Синтаксис Паскаля:case NUM of 1,2,3: writeln (‘Первый квартал’); 4,5,6: writeln (‘Второй квартал’); 7,8,9: writeln (‘Третий квартал’); 10,11,12: writeln (‘Четвертый квартал’) else writeln (‘Вы неправильно указали месяц’) end; Возможно end заменить на скобку).✅ 2021/03/27 13:32, Виталий Монастырский #3
Вот все-таки полезно иногда почитать чужие умные мысли. Насмотрелся на Вашу вакханалию с этими круглыми скобками аля-Лисп, и тут же мне пришла в голову идея как упростить синтаксис переключателей. А оно тут как раз и есть в подсказках на Паскале, хоть и немного в другом виде. Было: switch a case 1 оператор 1 case 2 оператор 2 case 3 оператор 3 case 4 оператор 4 else оператор 5
Стало: switch a 1 оператор 1 2 оператор 2 3 оператор 3 4 оператор 4 else оператор 5 (используется только если нужны операторы по умолчанию) :)
И проще, и быстрее, и меньше работы лексеру... ведь реально то этот "case" там вообще никаким образом не нужен. А потом ещё немного подумал и сделал так: Прерываемый переключатель: break sw a 1 оператор 1 2 оператор 2 3 оператор 3 4 оператор 4 else оператор 5
Непрерывный перекючатель: cont sw a 1 оператор 1 2 оператор 2 3 оператор 3 4 оператор 4 else оператор 5
А почему бы, собственно, и нет... вместо case будут два зарезервированных слова: break и cont, которые будут определять продолжаемость или прерываемость операторов проверки. Теперь у меня есть:break if cont if break unif break sw cont sw Похоже эта комбинация описывает вообще все возможные варианты проверки как сложных так и простых условий продолжаемым и прерываемым способом. И всего 6 служебных слов — break, cont, if, unif, sw, else. Учитывая, что это расширенная версия языка, а не ядровая — по-моему весьма не плохо. Решает все проблемы, не теряет удобочитаемости и понимаемости синтаксиса.
Так что — БЛАГОДАРЮ за хорошие идеи. :)✅ 2021/03/27 22:15, Виталий Монастырский #4
Итак, теперь у нас имеются новые переключатели. Точно таким же образом работают и множественные операторы переключения, с той лишь разницей, что они всегда сравнивают значения только с одним элементом и по сути выполняют только проверку — равно ли указанное в условии значение реальному значению проверяемого элемента. Общая схема таких операторов следующая:тип sw элемент значение команда 1 значение команда 2 значение команда 3 значение команда 4 else команда по умолчанию (если ни одно значение не подошло) Отдельно обратите внимание на то, что в операторе "sw" напротив каждого значения размещается только одна команда. Если Вам необходимо выполнить блок команд — размещайте его в одельном именованном блоке и выполняйте его через оператор безусловного перехода "doit".
Рассмотрим на примерах, как работают разные типы множественного переключения. Для начала рассмотрим работу непрерывного переключателя.a, b, c, d : 3, 2, 3, 5 z : 3 and sw z a команда 1 b команда 2 c команда 3 d команда 4 else команда 5 В данном случае будет выполнена команда 1 и команда 3, так как значение z=3 совпадает со значениями a и c.
Теперь рассмотрим работу прерываемого переключателя с выбором по Истине.z : 3 or sw z 1 команда 1 2 команда 2 3 команда 3 4 команда 4 В этом случае программа выполнит только команду 3 и сразу выйдет из данного блока проверки условия.
И, наконец, рассмотрим работу прерываемого переключателя с выбором по Ложному условию.a, b, c, d : 3, 3, 2, 5 z : 3 xor sw z a команда 1 b команда 2 c команда 3 d команда 4 В этом случае программа выполнит команды 1 и 2, так как значения a и b = z, а значит они соответствует истине. Но после этого программа сразу выйдет из блока проверки условия, так как третье проверяемое значение является ложным. Команды 3 и 4 выполнены не будут.
Преимущество переключателей в том, что их синтаксис позволяет указывать оператор выполнения сразу после значения условия, что дает очень компактную запись условного перехода.
✅ 2021/03/27 22:17, Виталий Монастырский #5
Ой, беда. Я похоже поломал Ваш сайт. Похоже, что у Вас в тегах не выполняется перенос предложений. Не знал. Извините. Учту.✅ 2021/04/01 14:45, Александр Коновалов aka Маздайщик #6
В языках Си и Паскаль метками оператора case могут быть только целочисленные константы (включая константы перечислимого типа). И это неслучайно, так сделано для повышения производительности. Если диапазон между наибольшей и наименьшей меткой сравнительно небольшой и метки в этом диапазоне уложены плотно (при этом веток с одинаковыми метками быть не должно), то вместо цепочки ветвлений переключатель компилируется в вычислимый goto:switch (n) { case 0: printf("zero"); break; case 1: printf("one"); break;
case 2: case 3: case 5: case 7: printf("prime %d", n); break;
case 4: case 6: case 8: case 9: printf("not prime %d", n); break;
default: printf("I don't know the number %d", n); } label jump[10] = { &zero, &one, &prime, &prime, ¬_prime, &prime, ¬_prime, &prime, ¬_prime, ¬_prime };
if (n < 10) goto jump[n]; else goto unknown;
zero: printf("zero"); goto exit; one: printf("one"); goto exit; prime: printf("prime %d", n); goto exit; not_prime: printf("not prime %d", n); goto exit; unknown: printf("I don't know the number %d", n); exit: В отличие от вложенных ветвлений, такая реализация переключателя обеспечивает более высокое быстродействие: переход на метку выполняется за небольшое константное время, не зависящее от числа меток.
Поэтому переключатель можно использовать в интерпретаторах байткода, где может быть около сотни различных машинных команд виртуальной машины:switch (program[pc]) { case ADD: … break; case SUB: … break; case JMP: … break; case CALL: … break; case RET: … break; … и ещё несколько десятков опкодов … default: fprintf(stderr, "BAD OPCODE %d AT %d!\n", program[pc], pc); abort(); } Быстродействие в случае цепочки if/else if/else if будет в дикие разы хуже.
Если язык допускает нецелочисленные метки для переключателя, либо переменные в метках, то переключатель в таком случае будет лишь синтаксическим сахаром для условного оператора.✅ 2021/04/03 00:00, alextretyak #7
Если диапазон между наибольшей и наименьшей меткой сравнительно небольшой и метки в этом диапазоне уложены плотно Данное условие для оптимизации конструкции switch соблюдать вовсе не обязательно, т.к. можно использовать HashMap {причём не простой HashMap, а на основе perfect hash function, т.к. все возможные ключи этого HashMap известны на этапе компиляции}, у него также сложность будет O(1).Если язык допускает нецелочисленные метки для переключателя Эта проблема аналогично решается с помощью HashMap, т.к. ключи у него вполне могут быть нецелочисленного типа, например строками.✅ 2021/04/04 13:02, Александр Коновалов aka Маздайщик #8
Спасибо, Алекс! Ценное дополнение.
Если брать целочисленные ключи из небольшого диапазона, то операция перехода выражается несколькими машинными инструкциями: проверкой на выход за границы, индексацией и переходом. Если веток около сотни (не редкость в интерпретаторах байткода), а тип проверяемой переменной однобайтовый (например, char в Си), то даже выход за границы проверять не обязательно — проще выделить массив 256 разных меток.
Хеширование потребует несколько больше команд, кроме того, компилятор должен уметь подбирать совершенную хеш-функцию для каждого набора значений). Посложнее, конечно, но я не удивлюсь, если это где-то уже реализовано.✅ 2021/04/04 13:13, Александр Коновалов aka Маздайщик #9
К чему я написал пред-предыдущий комментарий. К тому, что либо метки ветвей синтаксически должны быть константами, либо, когда метки могут быть произвольными выражениями (как в Go, например, или в языке Виталия), компилятор должен распознавать частный случай константных меток и компилировать его особым образом.
Практическая потребность в этом есть. Кроме того, пользователи языка будут ожидать, что выбор ветки переключателя выполняется за константное время.
Виталий в других темах утверждал, что программы в полном синтаксисе сначала упрощаются до подмножества, а затем подмножество компилируется в целевой код. Подмножество в языке Виталия (буду называть его так, поскольку, как показал Алекс, имя cup не однозначно) включает в себя только условные и безусловные переходы. Для эффективной компиляции переключателя в язык-ядро ему также следует добавить массивы меток (были в Алголе-60) и переход на метку из массива.✅ 2021/04/04 14:43, kt #10
Я бы ещё упомянул о таких GOTO, как переход по меткам с индексами в PL/1, типа dcl n fixed(31); n=1; goto m(n); … m(1): … m(2): ….
Или о такой экзотике, как метки-переменные и метки-массивы. // метка-массив dcl k (4) label static init(m1,m5,m10,m25); goto k(n); ... // метка-переменная dcl lab label; lab=m1;
m0:goto lab; m1:...lab=m2; goto m0; m2:...lab=m3; goto m0; ...
Эти механизмы удобны для программирования конечных автоматов, очень просты в реализации и сам переход всегда за константное время.✅ 2021/04/04 15:11, Автор сайта #11
Да, читая про массивы меток, мне первым делом подумалось про PL/1 :)✅ 2021/04/04 15:31, Александр Коновалов aka Маздайщик #12
Спасибо, Дмитрий Юрьевич, за ценное дополнение!
Метки-массивы видел в Алголе-60, о чём я упоминал. В Фортране, помню, параметром подпрограммы могла быть метка — подпрограмма могла возвращаться не в точку своего вызова, а прыгнуть куда-то. Например, на обработчик ошибки.
Сейчас перечитал сообщение об Алголе-60. Массивы меток были константными, описывались какswitch S := L1, L2, L3; … goto S[n]; Кроме того, тоже параметрами процедур могли быть метки. Переменных-меток не было.
В классическом Бейсике был операторON ‹выражение› GOTO 100, 150, 200, 300 Выражение вычисляло номер метки, на которую выполнялся переход. Если выражение вычислялось в 0, делался переход на метку 100, 1 — 150, 2 — 200, 3 — 300, в остальных случаях переход не выполнялся.
В общем, в старых языках возможности GOTO были богаче.
Впрочем, и в Си оператор switch довольно интересен: Устройство Даффа✅ 2021/04/04 15:58, kt #13
Метки-переменные и метки-массивы, это то, с чем мне пришлось столкнуться в PL/1 в первом же самостоятельном проекте (интерпретатор с ПРОЛ-2, 1987 год). Поскольку эти механизмы были просты и понятны — очень громоздкий конечный автомат заработал очень быстро (для новичка).
Лет через десять такими же механизмами мы вдвоем разрабатывали Систему Отладки м Моделирования СОМ. На спор уложились в 5 недель. Опять-таки из-за простоты и поэтому понятности. Ну и, конечно, X86 поддерживает — прямой командой перехода по адресу в переменной, т.е. прямо отображает переход по метке-переменной.✅ 2021/04/04 16:50, Автор сайта #14
Плавно и незаметно вышли на тему полезности goto, которая обсуждается в соседней ветке :)✅ 2021/04/04 18:29, kt #15
Это goto — какое надо goto )) Во всех примерах именно переключатели✅ 2024/12/01 00:00, alextretyak #16
Предлагаю обсуждение break в switch продолжить уже здесь, чтобы не разводить оффтоп на странице «Продолжение цикла и выход из него». (Начало обсуждения здесь: http://compiler.su/prodolzhenie-tsikla-i-vykhod-iz-nego.php#43)
Автор сайтапроваливание после case — 7 раз, Похоже, вы посчитали пустые case за "проваливание". Я считаю, их не нужно учитывать, т.к. фактически никакое "проваливание" в таких случаях не требуется: синтаксис языка программирования должен позволять выражать намерение программиста более явно, т.е. вместо case 30: case 31: лучше использовать запись case 30, 31: или аналогичную. И в данном файле реальное "проваливание" встречается только в одном месте: https://github.com/mortdeus/legacy-cc/blob/master/last1120c/c00.c#L129-L131 (Мой скрипт-анализатор также выдал только один этот случай проваливания для данного исходного файла.)заканчивается goto — 23 раза Похоже, вы посчитали все goto внутри всех case. Полагаю, что считать нужно только goto в конце case, т.к. только там они "конкурируют" с break. goto в конце case я насчитал в этом файле 16 штук (что, впрочем, тоже очень много).заканчивается return — 26 раз Аналогично. Вы посчитали все return внутри всех switch'ей. return в конце case в этом файле 18 штук.заканчивается exit — 2 раза exit внутри switch в данном файле всего один (в 356-й строке), причём расположен он не в конце case, поэтому я бы его вообще не стал учитывать. А за второй exit внутри switch вы, похоже, приняли вот этот — https://github.com/mortdeus/legacy-cc/blob/master/last1120c/c00.c#L444 Он располагается внутри if сразу после switch, но не внутри него.Не ахти какая статистика, но проваливание используется нечасто. Однако. Ваша статистика заставила меня крепко задуматься. Вы посчитали случаев "проваливания" в 7 раз больше, чем я. И всё равно по вашим цифрам получается, что «проваливание используется нечасто». Я почему-то решил считать не отдельные case'ы, в которых используется "проваливание", а switch'и, в которых есть хотя бы один case с "проваливанием". А ведь это очень большая разница! Допустим, у нас есть 10 switch'ей. И в каждом по 10 case'ов. Если "проваливание" используется только в одном-единственном case, то статистика по switch'ам покажет использование "проваливания" в 10% случаев. А статистика по case'ам — лишь в 1% случаев! Если пересчитать статистику по-новому, то в результате получаются такие цифры: Общее количество case'ов, не считая пустые: 326. Case'ов, в которых используется "проваливание": 13. Т.е. всего 4% (против 19%, если считать по-старому)! Если же говорить про исходный код ядра Linux 1.0, то "проваливание" используется только в 22 case'ах из 1143, т.е. лишь в 2% (против 7%) случаев!В отличие от then в Паскале после if условие. Там оно так себе А что не так с then в Паскале? На русский это слово переводится как «тогда» или «то» (и, например, в Глаголе используется именно такой перевод: https://atimopheyev.narod.ru/Glagol/otlichGO.htm), и получается что if a < 0 then return на русском можно записать как если а < 0 то возврат.Думаю, для проваливания вниз было бы уместно использовать ключевое слово then вместо fallthrough. Не уверен, что это хорошая идея. Хотя fallthrough мне тоже не нравится, несмотря на то, что именно такое ключевое слово используется во многих языках. Но давайте оставим выбор английского варианта названия тем, кто очень хорошо знает английский. Мне же гораздо интереснее выбрать русский вариант для этого ключевого слова. Может, у вас есть какие-то идеи? Я что-то так сходу удачного варианта подобрать не могу.
КлихальтПод уменьшением количества кода Вы верно имели ввиду уменьшение количества исходного текста программы, а не количества кода программы? Да. Ведь когда говорят, что «размер/объём программы: 100 тыс. строк кода», под «кодом» понимают исходный код (source code) программы [см. https://ru.wikipedia.org/wiki/Количество_строк_кода]. Объём сгенерированного компилятором машинного кода сейчас вообще мало кого интересует.позволю отослать Вас к приведённому мною примеру исходных текстов компилятора языка Си, где break вообще практически не используется для выхода из ветки оператора выбора. Хорошо. Только давайте быть более объективными. Да, конкретно в исходном файле last1120c/c00.c нет ни одного break в switch. Но вот в файле prestruct/c02.c break'ов в switch — 9, из них 6 располагается в конце case (причём не последнего в switch). Во всём исходном тексте этого компилятора таких break в switch — 10 штук. Т.е. тех, которые в конце не последнего case и которые можно убрать из кода/текста программы при использовании поведения «break по умолчанию». Псевдооператор "проваливания" потребуется (как я уже писал чуть выше) в 13 случаях. Результат (10 − 13) получается, конечно, не в пользу «break по умолчанию», но если посмотреть на статистику для исходного кода ядра Linux 1.0, то картина получится совсем иная. Псевдооператор "проваливания" потребуется (как я уже писал чуть выше) в 22 случаях. А вот таких break в switch, которые можно убрать из кода/текста программы при использовании поведения «break по умолчанию»: 498. Итого, количество строк кода (точнее, операторов в коде) сократится при таком поведении на 476 (498 − 22).✅ 2024/12/01 00:22, Gudleifr #17
Если уж перезапускаете тему, то начинайте, пожалуйста, сначала. Зачем нужен переключатель?✅ 2024/12/01 07:09, Вежливый Лис #18
интереснее выбрать русский вариант для этого ключевого слова. Может, у вас есть какие-то идеи? — Мама, я не могу остановиться!!! — Вперёд! Вперёд! Вперёд!
Вот это слово и исользовать: "вперёд".✅ 2024/12/01 10:33, Клихальт #19
Gudleifr, Зачем нужен переключатель? Согласен для начала следовало бы разобраться что именно мы обсуждаем.
Как мне видится оператор выбора в варианте классического языка Си с завершением конкретной ветки выбора при помощи одного из операторов безусловного перехода по необходимости представляет из себя один блок кода с множеством точек входа в него, а в варианте со скрытым по умолчанию оператором завершения конкретной ветки это оператор выбора одного из многих блоков кода (проваливание здесь некий компромисс и реверанс в сторону невозможности полностью исключить предыдущий вариант из кодирования ввиду его эффективности в ряде случаев). По своей сути это две разных конструкции, хотя и имеющих схожий внешний вид. Отсюда и некоторое недопонимание среди обсуждающих.
Ранее куда как чаще использовался первый вариант, сейчас этот стиль кодирования вытравливается из умов и навязывается совершенно другой.
Обсуждение вылилось в спор остроконечников и тупоконечников — в языке каким-то образом должны присутствовать оба варианта.
Мне ближе вариант чистого Си.✅ 2024/12/01 13:23, Gudleifr #20
Как мне видится Мне кажется, вопрос немного шире. Ведь "рядом" — в bash — if и switch — это две совершенно разные конструкции: первая анализирует код возврата программ, вторая — строковые константы. В Си попал только максимально упрощенный вариант переключателя — по int (ведь Си — это простейший компилятор), с явным намеком на то, что программист должен сам его "расширить", придав этим int какой-то особый смысл. Но как — непонятно.
Программисты этим путем не пошли, предпочтя else-if (пример из книги "Идеальный код"):/* matchhere: поиск соответствий регулярному выражению в начале текста */ int matchhere(char *regexp. char *text) { if (regexp[0] == '\0') return 1; if (regexp[l] == '*') return matchstar(regexp[0], regexp+2, text); if (regexp[0] == '$' && regexp[1] == '\0') return *text == '\0’: if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) return matchhere(regexp+1, text+1): return 0; } Так нужен ли переключатель вообще? Выше правильно указано, что он является практически аналогом BASIC-конструкции ON-GOTO. Но и в таком виде она не прожила долго. Помните, как быстро switch в анализаторе Win-сообщений был заменен таблицей, а затем макросом?
Есть "окно" в выборе не по "вводу", а по "состоянию". Если реализовать ДКА "в лоб"... Например, программируя что-то вроде:
https://studfile.net/html/1549/349/html_yyEckH1eTr.fjB9/img-3fukaW.png ,
мы можем пройти от 1-го до 6-го состояния, "не выходя наружу", тупо "проваливаясь".
"Компилируя" автоматы, мы можем прийти к идее программы с вариантами, где "нормальный процесс" — "проваливание" от точки входа до конца.
ООП и здесь дает обходной путь (как в итераторах): определив в суперклассе метод "go" мы можем переопределить его во всех наследниках, заменив int ссылкой на объект, имеющий нужное поведение...
Как-то так.✅ 2024/12/01 18:57, Неслучайный читатель #21
Java, традиционный переключатель:private static void printGreetingBasedOnInput(String input){ switch (input){ case "hello": System.out.println("Hi There"); break; case "goodbye": System.out.println("See you Later!"); break; case "thank you": System.out.println("You are welcome"); break; default: System.out.println("I don't understand"); break; } } Тоже Java, сопоставление с образцом:private static void printGreetingBasedOnInput(String input){ switch (input){ case "hello" -> System.out.println("Hi There"); case "goodbye" -> System.out.println("See you Later!"); case "thank you" -> System.out.println("You are welcome"); default -> System.out.println("I don't understand"); } } Два варианта синтаксиса, в первом — проваливание по умолчанию, а во втором проваливания нет.✅ 2024/12/01 19:42, Вежливый Лис #22
Два варианта синтаксиса И что теперь, нам всем по два варианта делать? Какие ваши аргументы за то, что именно наличие двух вариантов — это лучший подход из желательных?✅ 2024/12/01 20:37, Клихальт #23
Gudleifr,Программисты этим путем не пошли, предпочтя else-if (пример из книги "Идеальный код"): Извините, что не по теме обсуждения, но что-то слишком уж много очепяток в вашем примере.✅ 2024/12/01 20:41, Неслучайный читатель #24
уместно использовать ключевое слово then вместо fallthrough. не уверен, что это хорошая идея. Хотя fallthrough мне тоже не нравится... Но давайте оставим выбор английского варианта названия тем, кто очень хорошо знает английский. Мне же гораздо интереснее выбрать русский вариант для этого ключевого слова. Русское слово затем, которое, кстати, переводится на английский как then. по два варианта делать? Какие ваши аргументы за то, что именно наличие двух вариантов — это лучший подход из желательных? Никаких аргументов, просто констатация фактов строго по теме. Интересно, оптимизатор кода может сам увидеть, что код без проваливаний преобразовать в аналогичный с проваливаниями:switch (i) { // по умолчанию нет проваливания case "abc"-> print ("A"); print ("B"); print ("C"); case "bc"-> print ("B"); print ("C"); case "c"-> print ("C"); } А это аналогичный с проваливаниями:switch (i) { // проваливание есть case "abc": print ("A"); case "bc": print ("B"); case "c": print ("C"); } ✅ 2024/12/01 20:48, Gudleifr #25
но что-то слишком уж много очепяток Да, это не по теме. Пример не мой, а Кернигана.❔ 2024/12/02 00:00, alextretyak #26
КлихальтВот тексты первого компилятора Си, написанного на Си: https://github.com/mortdeus/legacy-cc Вообще, судя по описанию (http://cm.bell-labs.co/who/dmr/primevalC.html), там два Си компилятора или две версии одного компилятора, написанные в 1972-73 гг., когда сам язык Си ещё только-только появлялся. И всё указывает на то, что в окружении, в котором разрабатывался более ранний из них — last1120c — оператор break в switch вообще не поддерживался. Поэтому считать количество его присутствия было довольно глупо. :)(: Так, в .c файлах в директории last1120c действительно нет ни одного break в switch. Его логика эмулируется через goto. Я решил это исправить {"осовременить" этот исходный код, заменив goto на break где это возможно, с моими изменениями можно ознакомиться по ссылке: https://github.com/alextretyak/legacy-cc/commit/01b639d} и посчитать статистику снова. Теперь количество break в switch, которые можно убрать из кода/текста программы при использовании поведения «break по умолчанию» стало 27 (против 10 в оригинальной версии). Напомню, что псевдооператор "проваливания" потребуется лишь в 13 случаях. Данная статистика опровергает вот это ваше утверждение:Ранее куда как чаще использовался первый вариант Так как 27 > 13. Кому-то может не понравиться тот факт, что такая статистика является некой «средней температурой по репозиторию». Вот статистика раздельно по двум этим компиляторам: last1120c: 12 > 5. prestruct: 15 > 8.сейчас этот стиль кодирования вытравливается из умов и навязывается совершенно другой. Да, кодирование в стиле «лапши из goto» с тех пор активно вытравливается. :)(: Но что в этом плохого?
И как бы это неприятно не было для вас, но я считаю, что эти полученные результаты вполне убедительно развеивают миф, что есть какой-то там более совершенный ранний стиль кодирования, при котором поведение «проваливание по умолчанию» даёт некое преимущество.❔ 2024/12/02 00:11, Gudleifr #27
Но что в этом плохого? Ничего. Обычная вкусовщина.❔ 2024/12/02 13:19, Gudleifr #28
есть какой-то там более совершенный ранний стиль кодирования, при котором поведение «проваливание по умолчанию» даёт некое преимущество Есть целых три стиля, окромя обсуждаемого злесь масштабирования: 1. В "плюем и копипастим", проваливание позволяет обособить наиболее общий участок кода. И сэкономить на прямом кодировании автоматов. 2. В структурном оно не играет особой роли, т.к. даже без него см. выше пример Кернигана — return всех помирит. 3. В проблемно-ориентированных языках switch если и реализуется, то "поперек". См. например Win-FOBOS https://gudleifr.forum2x2.ru/t35-topic#308 .❔ 2024/12/02 16:45, Клихальт #29
alextretyak,оператор break в switch вообще не поддерживался. Поэтому считать количество его присутствия было довольно глупо. :)(: Возможно и так, но по вашей ссылке я не увидел данного утверждения. Может поделитесь цитатой?Да, кодирование в стиле «лапши из goto» с тех пор активно вытравливается. :)(: Но что в этом плохого? Вытравливается не "кодирование в стиле «лапши из goto»", а его использование как таковое в любом контексте. Разве не так?убедительно развеивают миф, что есть какой-то там более совершенный ранний стиль кодирования Вот хлебом Вас не корми, дай какой нибудь миф развеять. А ведь в данном случае единственный миф это само существование развенчиваемого Вами мифа. Во всяком случае я к нему не имею никакого отношения — никогда не утверждал такового, а приводил эти исходные тексты лишь для примера стиля, отличного от современного нам и активно навязываемого, т.е. как пример просто другого и только.
Кстати, камешек в копилку предыдущей темы, из обсуждения коей и вышла эта — в приведённых мною текстах компилятора (версия last1120c) программист при помощи goto эмулирует отнюдь не только break в switch, но и continue из вложенного во внешний цикл и безконечные циклы с выходом из середины. Там вообще много интересных моментов. Добавить свой отзыв
Написать автору можно на электронную почту mail(аt)compiler.su
|