LINUX.ORG.RU

Зачем писать statement в последней пустой секции switch?

 , ,


1

5

Итак, есть какой-то такой говнокод:

enum Whatever { ONE = 1, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT };

void foo(Whatever v) {
    switch (v) {
    case ONE:
    case TWO:
    case SIX:
        std::cout << v << std::endl;
    case THREE: // fallthrough
    default:
       break; // без хотябы ";" не компилируется: 
              // error: expected primary-expression before '}' token
    }
}

Вопрос: как ничего не делать и жить счастливо зачем в конце обязателен какой-нибудь statement? Почему что мешает сделать как в случае fallthrough?

потому что.

можно написать default:; это работает и почти не мешает любоваться кодом.

вообще можно не писать default вообще но компиляторы ворнингами кидаются иногда если что-то not handled.

i36_zubov
()

Почему что мешает сделать как в случае fallthrough?

Так именно же fall до следующего встретившегося выражения. Зачем метка в никуда?

gag ★★★★★
()

Не понятно что ты хочешь. Хочешь без default, пиши без default. Хочешь с ним, то зачем-то ведь он тебе нужен? Или ты именно точкусзапятой писать не хочешь?

unt1tled ★★★★
()

ты пользуешься языком из докембрия и ещё задаешь глупые вопросы. Ты ещё удивись, что до С++11 нужно было писать вложенные шаблоны с пробелом в >>

former_anonymous ★★★
()

Потому что case: и default: являются метками, а метки всегда относятся к statement, перед которым они стоят. break; и даже одинокий ; являются statement, но если их убрать, то метке будет не к чему прицепиться.

ddos3
()
Ответ на: комментарий от grondek

Плохая практика. Если добавишь через много лет новое значение в enum, то компилятор поругается на свитчи, в которых ты забыл добавить его обработку. А если есть default - то не будет ругаться.

ddos3
()
Ответ на: комментарий от gag

Зачем метка в никуда?

Как будто после switch начинается «никуда». Надо бы сказать чувакам с коллайдером чтоб не тратили силы зря, пусть лучше займутся C или C++

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от unt1tled

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

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от ddos3

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

ddos3
()
Ответ на: комментарий от ddos3

Плохая практика. Если добавишь через много лет новое значение в enum, то компилятор поругается на свитчи, в которых ты забыл добавить его обработку. А если есть default - то не будет ругаться.

Вообще — да, но иногда енумы бывают уж слишком большими. Ну и к тому же раньше enum использовали для compile-time констант (сейчас это делается через constexpr).

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от ddos3

Плохая практика. Если добавишь через много лет новое значение в enum, то компилятор поругается на свитчи, в которых ты забыл добавить его обработку. А если есть default - то не будет ругаться.


enum EShit
{
 eShit_1,
 eShit_2,

 //-----
 eShit_Count
};

...

void GrabSomeShit(EShit inShit)
{
  static_assert(eShit_Count == 2, "Update code below");
  switch (inShit)
  {
    case eShit_1:
      One();
      break;

    case eShit_2:
      Two();
      break;

    default:
      assert(false); // fucker!
      break;
  }
}
Pavval ★★★★★
()
Ответ на: комментарий от Pavval

Ну замечательно же. Зачем получать сообщение об ошибке от компилятора сразу же после того, как добавил новое значение, если можно «за те же деньги» получить внезапное падение продакшна через два месяца в 3 часа ночи в пятницу, когда он на этом ассерте внезапно упадет? Намного веселее же!

ddos3
()
Ответ на: комментарий от ddos3

А, сорри, не заметил static_assert вверху. Да, такой костыль будет работать, но это именно костыль, который нужно не забыть водрузить перед каждым свитчем. Если где-то забыл - привет падение продакшена.

ddos3
()

Для порядочка, я бы вообще запретил писать, например

if(boo()) blabla();
, а оставил только
if(boo())
{
 blabla();
}

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

ilovewindows ★★★★★
()

А ещё некоторые кодинг-стандарты если нет break, требуют писать комментарий почему там fallthrough. Так что проще написать

default:
  break;

И компилятор счастлив, и кодинг-стандарт.

sergej ★★★★★
()

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

mashina ★★★★★
()
Ответ на: комментарий от ddos3

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

1. «Забыть» сложно, когда это общепринятая практика в проекте. И код-ревью тоже помогают.

2. У нас вместо «assert()» стоит непадающий аналог с логгингом трейса. Дополнительно как элемент defensive programming всегда пишется fallback код, который оставит продакшен в consistent состоянии. Это касается всех проверок в коде, а не только этой.

3. Следующим уровнем защиты стоит Coverity.

И да, есличе, не все конпеляторы дают ворнинг на неполный switch. С этого и стартуем.

Pavval ★★★★★
()
Ответ на: комментарий от sergej

кодинг-стандарты

Не то, чтоб я хотел сказать, что кодинг-стандарты — это плохо. Но кодинг-стандарты слепы и иногда уродуют случаи, когда код есть предельно ясный и красивый но не по стандарту. По сему применение common-sense всегда должно стоять выше стандартов. А для недоходчивых можно написать такой пункт в стандарте:

0. Use common sence when applying rules/principles from this standard

К чему я это: в случае когда вообще требуется обработать только часть значений default писать вообще не есть обязательным (однако стоит оставить короткую заметку, что не все значения обрабатываются)

KennyMinigun ★★★★★
() автор топика
Ответ на: комментарий от Pavval

Ок, я понял. У вас ущербные компайлеры, поэтому костыли с подпорками. Как раз тот случай, когда красивая теория разбивается о суровую практику жизни :) Главное понимать, что это у вас вынужденная мера а не good practice.

ddos3
()
Ответ на: комментарий от KennyMinigun

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

Как раз в этом случае default нужно писать, потому что он и есть пометка «мы сознательно обрабатываем не все значения». И в отличие от комментария, эта пометка будет понятна не только программисту, но и компилятору.

ddos3
()
Ответ на: комментарий от ddos3

Как раз в этом случае default нужно писать, потому что он и есть пометка «мы сознательно обрабатываем не все значения». И в отличие от комментария, эта пометка будет понятна не только программисту, но и компилятору.

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

А то один сделал, а второй потом добавил элемент в enum и забыл обновить этот switch(). И оно все продолжает смотреться словно так и надо. И особенно весело с коментарием.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

Если перебирается enum - согласен. Так будет правильнее.

ddos3
()

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

foo//not defined

switch,//валится тут, на первом же проходе, даже не глядя на код

А что уж говорить о, с позволения сказать, языке, который, с позволения сказать, напейсали трупы страусов

portquest2016
()
Ответ на: комментарий от portquest2016

Чушь. Это всего лишь особенности синтаксиа без практического умысла. В С/С++ метка всегда является частью высказывания и самый простой вараинт с меткой это LABEL: + пустое высказывание которое должно оканчиваться ';'. case и default сделаны по аналогии с goto метками.

Почему что мешает сделать как в случае fallthrough?

В случае с fallthrough, кстати, тоже стоит ';' в конце выражения как и с метками

LABEL1: LABEL2: ;

mashina ★★★★★
()
Ответ на: комментарий от portquest2016

Здесь то появляется не ещё один вариант синтаксической конструкции, а правило автоматической расстановки ';', как в JS, или не появляется. В парсере оно реализауется одинаково для всех высказываний.

Да, это усложняет парсер, но не делает каких-либо «оптимизаций» в кол-ве проходов и не помогает в устранении неоднозначностей. Ключевые же слова, твой пример с switch, именно что помогают устранять неоднозначности и делать разбор контекстно независимым.

mashina ★★★★★
()

Язык древний - вот и нужно.

Я бы перечислил все варианты или впихнул бы unreachable().

RazrFalcon ★★★★★
()
Ответ на: комментарий от ilovewindows

Для порядочка, я бы вообще запретил писать, например if(boo()) blabla();

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

DELIRIUM ☆☆☆☆☆
()
Ответ на: комментарий от ilovewindows

Это бред, у меня даже было из нескольких операторов в 1 строку и кончалось break. Ошибку подобного рода можно допустить разве что если ты пишешь на си впервые, поскольку при необходимости увеличить сложность до нескольких стейтментов ты переписываешь c блоком автоматически и не задумываясь, это оооочень маловероятно, допустить такую ошибку, и сразу бросается в глаза.

anonymous
()
Ответ на: комментарий от anonymous

Это бред, у меня даже было из нескольких операторов в 1 строку

Хоть в несколько, хоть в одну. Самое главное, что даже если там только одно выражение, всё равно обязательно окружить фигурными скобками. Чтобы после добавления второго не искать ошибку: т.к. в этом месте её обнаружить будет очень сложно. Оно не бросается в глаза.

Хотя, против одной строки есть довод. Отлаживать сложнее: хочешь остановится при выполнении условия, а можешь только постоянно на целом ифе.

gag ★★★★★
()
Ответ на: комментарий от gag

Сколько не попадалось кода, ни разу не было проблем. Взгляд сам ложится туда, потому что «ну а вдруг?», а в своём крайне маловероятно. Это из той же оперы, что и боязнь перед goto. Иногда стоит применять, иногда нет, зависит от задачи.

anonymous
()
Ответ на: комментарий от MKuznetsov

А ещё на нём есть кооперативный мультитаскинг / coroutines. (Но лучше бы Линусу предложили наконец настолько хороший концепт, что он не смог бы его сравнять с землёй, а внедрил).

gag ★★★★★
()
Ответ на: комментарий от former_anonymous

О, как же я с этим дерьмом мучался. Как долго в школе не мог понять, фигли оно не работает. Жаль тогда 11 стандарт вот только-только выходил.

Deleted
()

а ты представь ситуацию, что тебе нужно сделать по умолчанию? Как ты будешь жить без default?

А никак. Просто в твоём случае у тебя поведение по умолчанию отсутствует. Всё логично, нет?

reprimand ★★★★★
()
Ответ на: комментарий от Deleted

Посмотри на switch-case как на goto-label. Тогда вся магия развеивается.

gag ★★★★★
()
Ответ на: комментарий от Pavval

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

Kuzy ★★★
()

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

deep-purple ★★★★★
()
Ответ на: комментарий от deep-purple

Как уже написали выше — компилятор резко меня опускает, если не обработать «все» значения из enum. Тупо, но тому есть свои причины.

Но вот писать пустой стейтмент после метки — это просто недоработка синтаксиса. Ведь итак понятно, куда пойдёт контроль если перейти по метке.

KennyMinigun ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.