switch(i) {
case 0:
action0(); // заметьте, оператор break далее пропущен специальноcase 1:
action1(); // итого, это действие выполнится при i равном как 1, так и 0break;
}
C#-пример (аналог):
switch(i) {
case 0:
action0();
goto case 1; // goto? прикольно! а почему без этого никак? :-)case 1:
action1();
break;
}
Только один комментарий: это не holywar, просто забавно.
Здравствуйте, rsn81, Вы писали:
R>Почему: прозрели?
Потому что пример написан таким образом, что порядок следования case-ов имеет значение. Я так никогда не писал, не смотря на то, что плюсы это тоже позволяют. Если нужна указанная логика, правильным будет в action1() первой строкой написать вызов action0().
Здравствуйте, fmiracle, Вы писали:
F>На самом деле это ключевой момент. F>Сделано для большей простоты осознания поведения программы. Потому что в большинстве случаев case сопровождается break и отсутствие его в данном конкретном месте может быть запросто незамечено человеком.
Для простоты осознания нужно было дополнить break его собратом continue:
switch(i)
{
case 0:
action0();
continue;
case 1:
action1();
break;
}
switch(i) {
R> case 0:
R> action0(); // заметьте, оператор break далее пропущен специально
R> case 1:
R> action1(); // итого, это действие выполнится при i равном как 1, так и 0
R> break;
R>}
C#-пример (аналог):
switch(i) {
R> case 0:
R> action0();
R> goto case 1; // goto? прикольно! а почему без этого никак? :-)
R> case 1:
R> action1();
R> break;
R>}
Только один комментарий: это не holywar, просто забавно.
Здравствуйте, rsn81, Вы писали:
R>Гм... даже не знаю, как серьезно ответить... Ну чтобы компилятору сделать приятно.
Не, я не то имел ввиду, но я заблуждался
Я предположил, что раз уж в C# не работает переход к следующему case-у без goto, то и break в конце case не нужен. Имхо логично, компилятор вполне в состоянии сам передать управление за пределы switch-а. Оказывается, это не так.
Здравствуйте, rsn81, Вы писали:
R>Здравствуйте, serg_fork, Вы писали:
_>>Вот бы вам за этот пример руки поотрывать R>Почему: прозрели?
1. Если вам нужно сделать что-то не зависимо от кейса, то почему бы это не вынести вверх, зачем городить goto?
action1();
switch (i)
{
case 0:
action0();
.....
break;
case 1:
.....
break;
case n:
}
2. Если все же это действие выполняеться лишь в нескольких кейсах, то просто завести action2() в котором и реализовать вызов нужных операций.
Возвращаясь к теме — почему в жаве можно а шарпе нельзя — не знаю, но думаю что это неочевидно и не наглядно, можно забыть про break, и такое начнется : ))))
Здравствуйте, hell citizen, Вы писали:
HC>Потому что пример написан таким образом, что порядок следования case-ов имеет значение.
Вот именно.
Причем, если уж продолжать мысль: в Java можно делать таким образом переход только последовательно на следующий case, то с помощью goto C# позволяет абсолютно произвольно скакать по блокам case.
HC> Я так никогда не писал, не смотря на то, что плюсы это тоже позволяют.
А я частенько на Java.
HC> Если нужна указанная логика, правильным будет в action1() первой строкой написать вызов action0().
Нет, это не будет правильным.
Посмотрите внимательно: для 1-цы не нужно выполнять действия 0.
Здравствуйте, serg_fork, Вы писали:
_>1. Если вам нужно сделать что-то не зависимо от кейса, то почему бы это не вынести вверх, зачем городить goto?
Если бы в примере первым поставил case с каким-то действиями 3 и с break-ом в конце, вас бы устроило?
_>2. Если все же это действие выполняеться лишь в нескольких кейсах, то просто завести action2() в котором и реализовать вызов нужных операций.
Обычно это примитивные действия, шкурка выделки не стоит.
_>Возвращаясь к теме — почему в жаве можно а шарпе нельзя — не знаю, но думаю что это неочевидно и не наглядно, можно забыть про break, и такое начнется : ))))
А goto в современных языках вроде давно уже признанный моветон.
Здравствуйте, serg_fork, Вы писали:
_>думаю что это неочевидно и не наглядно
switch(0) {
case 0: // переход к case 1case 1:
break;
}
switch(0) {
case 0:
;
goto case 1; // переход к case 1case 1:
break;
}
А вот это наглядно? Я понимаю, что с точки зрения компиляции это абсолютно разные примеры, но просто на глаз — очень не интуитивно.
PS Я не издеваюсь ни над кем... обидчивые вы мои, кто поставил "минусы" даже не аргументировав свою обидку, так как сам работаю на .NET, просто мне показалось забавной эта особенность компилятора.
Здравствуйте, rsn81, Вы писали:
R>Причем, если уж продолжать мысль: в Java можно делать таким образом переход только последовательно на следующий case, то с помощью goto C# позволяет абсолютно произвольно скакать по блокам case.
Не хочу начинать СВ, но это не тот случай, когда goto помогает. В этом случае лучше реализовать конечный автомат.
Обязательно бахнем! И не раз. Весь мир в труху! Но потом. (ДМБ)
switch(i) {
R> case 0:
R> action0(); // заметьте, оператор break далее пропущен специально
R> case 1:
R> action1(); // итого, это действие выполнится при i равном как 1, так и 0
R> break;
R>}
C#-пример (аналог):
switch(i) {
R> case 0:
R> action0();
R> goto case 1; // goto? прикольно! а почему без этого никак? :-)
R> case 1:
R> action1();
R> break;
R>}
Только один комментарий: это не holywar, просто забавно.
нуууу, не знааааююююю
if (_ == 0)
action0();
action1();
отэто типа имелось в виду?
на самом деле вышеописанная ситуация — явная заплатка на чём-то
да и вообще, жава-шарповские свитчи слабенькие...
я уж молчу, что есть языки без break-ов
Здравствуйте, rsn81, Вы писали:
_>>Возвращаясь к теме — почему в жаве можно а шарпе нельзя — не знаю, но думаю что это неочевидно и не наглядно, можно забыть про break, и такое начнется : )))) R>А goto в современных языках вроде давно уже признанный моветон.
В принципе, switch — не меньшее зло, чем goto. А тут все сразу.
PhantomIvan wrote:
> отэто типа имелось в виду? > на самом деле вышеописанная ситуация — явная заплатка на чём-то
Мне это показалось удобным в следующей ситуации:
switch(currentVersion)
{
case 1:
...
upgradeDocumentFromV1toV2();
...
case 2:
...
upgradeDocumentFromV2toV3();
...
case 3:
....
}
Т.е. очень удобно добавлять в конец switch автоматические апдейты любой версии документа до последний.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
А>Т.е. очень удобно добавлять в конец switch автоматические апдейты любой версии документа до последний.
1. я бы заюзал Version — класс, который в дотнете имеет место быть, и весьма полезен
2. может быть, расширил бы его (включить бы инфу о дате и т.п.)
3. написал бы обобщённый обработчик "поднятия" до текущей версии
4. внутри него, само собой, был бы цикл
короче я думал над подобной мулькой, пока что не написал её, т.к. не нужно пока
PhantomIvan wrote:
> А>Т.е. очень удобно добавлять в конец switch автоматические апдейты > любой версии документа до последний. > > 1. я бы заюзал Version — класс, который в дотнете имеет место быть, и > весьма полезен > 2. может быть, расширил бы его (включить бы инфу о дате и т.п.) > 3. написал бы обобщённый обработчик "поднятия" до текущей версии > 4. внутри него, само собой, был бы цикл > > короче я думал над подобной мулькой, пока что не написал её, т.к. не > нужно пока
Это называется переусложнение. У меня простая ситуация — версия всегда "+1" (а зачем может понадобится больше? при
необходимости даты легко находятся по истории исходников). Добавление апдейта до новой версии заключается в изменении в
исходнике текущей на +1 и добавлении очередного "case".
Мыслить надо проще.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, SergH, Вы писали:
SH>Я предположил, что раз уж в C# не работает переход к следующему case-у без goto, то и break в конце case не нужен. Имхо логично, компилятор вполне в состоянии сам передать управление за пределы switch-а. Оказывается, это не так.
На самом деле это ключевой момент.
Компилятор может многое, но при дизайне шарпа сознательно отказались от "проваливания" между ветками case и запретили case (а так же default) без break
Сделано для большей простоты осознания поведения программы. Потому что в большинстве случаев case сопровождается break и отсутствие его в данном конкретном месте может быть запросто незамечено человеком.
То, что туда можно напихать goto, чтобы получить возможности от которых дизайнеры языка сознательно отказывались, да еще и более ненаглядно сдлеать — ничего не значит. При определенном старании можно все что угодно испоганить
А>Это называется переусложнение. У меня простая ситуация — версия всегда "+1" (а зачем может понадобится больше? при
когда будет по 10 изменений формата в месяц, поймёшь (и возникнет проблема глюков в цепочке конвертации — за всем не уследишь)
А>необходимости даты легко находятся по истории исходников). Добавление апдейта до новой версии заключается в изменении в А>исходнике текущей на +1 и добавлении очередного "case".
см. рефакторинг "замена условных операторов полиморфизмом", его обоснование, и область применения (Фаулера советую)
А>Мыслить надо проще.
Среди многих плохих идей, представленных на доске позора, идея оператора goto подвергалась наибольшей критике. В языках программирования этот оператор является непосредственным двойником машинной инструкции перехода и может использоваться для конструирования условных и повторяющихся операторов. Но он также дает возможность программистам конструировать запутанный или беспорядочный поток выполнения программы, игнорировать какую-либо регулярную структуру. Это затрудняет, если не делает невозможными, структурные рассуждения о таких программах.
Нашими основными средствами для понимания сложных объектов и управления ими являются структура и абстракция. Мы разбиваем чрезмерно сложный объект на части. Спецификация целого основывается на спецификации его частей. Оператор goto стал прототипом плохой идеи языка программирования, поскольку он может разрушить границы между частями и сделать недействительными их спецификации.
Из этого следует, что язык должен допускать, стимулировать и даже навязывать формулирование программ в виде должным образом вложенных структур, в которых свойства целого могут быть выведены из свойств частей. Рассмотрим, например, спецификацию повторения R оператора S. В этом случае S является частью R. Покажем две возможные формы:
R0: while b do S end
R1: repeat S until b
Ключом к надлежащей вложенности является возможность вывода свойств R из свойств S. Например, если условие (утверждение) P остается справедливым (является инвариантом) при выполнении S, то мы заключаем, что P останется инвариантом, когда выполнение S будет повторяться.
Правила Хоара (Sir Charles Antony Richard Hoare) выражают это формально следующим образом:
{P & b} S {P} влечет {P} R0 {P & b}
{P} S {P} влечет {P} R1 {P & b}
Однако если S содержит оператор goto, то по поводу S невозможно сформулировать какое-либо подобное утверждение, и, следовательно, невозможен какой-либо дедуктивный вывод относительно действия R. Это очень значительная потеря. И действительно, практика показывает, что большие программы без goto гораздо проще понимаются, и гораздо проще обеспечить какие-либо гарантии относительно их свойств.
Об операторе goto говорилось и писалось достаточно, чтобы убедить почти каждого, что это основной пример плохой идеи. Тем не менее, создатель языка Pascal (Напомним, что автором языка Pascal является сам Никлаус Вирт. — С. Кузнецов) оставил в языке оператор goto, а также оператор if без закрывающего символа end. Очевидно, ему не хватило смелости нарушить традицию, и он пошел на ошибочные уступки традиционалистам. Но это было в 1968 г. Теперь почти все понимают суть проблемы, за исключением разработчиков позднейших коммерческих языков программирования, таких как C#.
2. switch:
Если некоторое средство представляет собой плохую идею, то средства, построенные поверх его, оказываются еще хуже. Это правило можно продемонстрировать на переключателе, который, по существу, представляет собой массив меток. Например, в предположении наличия меток L1, : L5 объявление переключателя в языке Algol могло бы выглядеть следующим образом:
switch S := L1, L2, if x < 5 then L3 else L4, L5
Тогда несомненно простой оператор goto S[i] является эквивалентным следующему:
if i = 1 then goto L1 else
if i = 2 then goto L2 else
if i = 3 then
if x < 5 then goto L3 else goto L4 else
if i = 4 then goto L5
Если goto стимулирует беспорядок в программировании, то переключатель делает его неизбежным.
В 1965 г. Хоар предложил наиболее подходящую замену переключателя — оператор case. Эта конструкция представляет собой правильную структуру, в которой операторы-компоненты выбираются в соответствии со значением i:
case i of
1: S1 | 2: S2 | ........... | n: Sn
end
Однако разработчики современных языков программирования решили игнорировать это элегантное решение в пользу гибрида переключателя языка Algol и структурного оператора case:
case statement:
switch (i) {
case 1: S1; break;
case 2: S2; break;
: ;
case n: Sn; break; }
Символ break либо обозначает разделитель между последовательными операторами Si, либо действует как goto на конец конструкции переключателя. В первом случае он является избыточным, а во втором — это замаскированный goto. Этот пример происходит из языка C — плохая концепция в плохой нотации.