Какие полезные альтернативные структуры управления вы знаете? [закрыто]

12

Подобный вопрос был закрыт на SO.

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

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

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

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

Ответы должны дать идеи для нового языка программирования или улучшения реального языка.

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

Это про императивное программирование.

Maniero
источник
1
Почему этот вопрос должен касаться «императивного программирования»?
фактор
@missingfaktor: Потому что структуры управления - это императивное программирование. Конечно, некоторые проблемы могут быть решены с помощью функционального подхода или иным способом, но другие парадигмы не ставят контрольные структуры в центр развития. Но в любом случае вы можете быть креативным.
Маньеро
3
Ну, я собирался поделиться Pattern Matching с Guards, так как они более общие, чем заявления Case и If-Thens, но если это не зона FP, я думаю, это просто больше Pattern Matching для остальных из нас!
CodexArcanum
@CodexArcanum: Ну, Pattern Matching - это конструкция, очень похожая на императивные. Действительно, само сопоставление с образцом является альтернативой императивным структурам управления. Не стесняйся ;-)
Маньеро
Глядя на все ответы, я рад, что ни одно из предложений не существует в реальной жизни (и, надеюсь, никогда не будет). Извините :)
serg

Ответы:

14

ОК, это забавный вопрос.

Я также хотел бы иметь общее elseдля циклов while и for, когда условие не выполняется в первом тесте:

while (condition) {
    // process
}
else {
    // condition was never true
}

Это позволяет избежать неловкого пересчета условия или сохранения его в переменной.

Макнейл
источник
Python имеет это.
Барри Браун
Привет! Наконец, странный выбор Python, с которым я согласен! ;-)
Макнейл
5
Нет. Предложение else в Python для циклов for / while выполняется, если цикл заканчивается нормально, что означает, что цикл не завершается с помощью оператора break или return или исключения. В циклах for класс else выполняется после того, как исчерпана последовательность зацикленных элементов, а в циклах while он выполняется после того, как условие цикла в первый раз оценивается как False.
pillmuncher
4
Есть запрос на добавление while ... elseконструкции так, как Macneil описывает ее в PHP. Я думаю, что это отличная идея, потому что «вот результаты / результатов не было» - довольно распространенная идиома в веб-приложениях.
Дин Хардинг
1
@SnOrfus: он хочет блок кода (отдельный от блока цикла), который выполняется ТОЛЬКО, если условие while никогда не выполняется. Do-while выполняет блок кода цикла (а не какой-то отдельный блок) один раз, независимо от условия while.
Легион
10

Почему бы не смешать несколько ответов в один?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

Расширяемый обобщенный синтаксис конструкции управления потоком на императивном языке был бы весьма полезным и интересным. Пока это не появится, думаю, я просто буду использовать Лисп или что-то в этом роде.

Джон Перди
источник
5
Не полезно, сбивает с толку. Не занимательно, медленно.
Джош К
2
@ Джош К: Да, ты прав. Что, ты думал, что я не согласен? Этот ответ кусает язык, чтобы не рассмеяться.
Джон Пурди
Если это иронично, то это обязательно получится!
Джош К
11
+1 заставил меня смеяться. Для выполнения кода между итерациями необходимо условие «между».
Барри Браун
1
+1, но это seventh { ... }тоже нужно .
j_random_hacker
7

Управляющие структуры как функции.

Я хочу for, if, else, whileи т.д. , чтобы быть функции, а не специальные структуры.

Я хочу return, try/exceptи gotoбыть производными продолжения.

Это, конечно, связано не столько с конкретной структурой управления, сколько с тем, как вы видите структуры управления в целом, с мета структур управления.

dietbuddha
источник
2
Продолжения представляют собой тяжелую концепцию для языка, и есть веские причины не использовать их во многих языках.
Дэвид Торнли
Я не согласен; имея for, if, elseи whileкак функция заставляет меня сделать вывод , что параметры этих функций должны быть выполнены лениво, чтобы вести себя так же , как оригинальные конструкты. Иметь возможность выполнять ленивое выполнение было бы неплохо.
Ученик доктора Вилли
1
@ Дэвид: То, что они есть, не означает, что вы должны их использовать. Обычные программисты могут использовать то, к чему они привыкли return, исключения и т. Д. Но теперь у опытного программиста есть мощный дополнительный инструмент в его наборе инструментов, если возникнет такая необходимость. Кроме того, языки ИМХО не должны быть «заглушены». Языки должны обладать способностью поддерживать растущий опыт и знания CS.
dietbuddha
1
@dietbuddha: (продолжение) Я не говорю, что продолжения плохие, я говорю, что они тяжелые, и их использование пригодно для языка, что-то вроде исключений. Кроме того, наличие продолжений может вызвать изменения в том, как люди используют язык, как, например, исключения в C ++. Язык, который поддерживает продолжения, будет отличаться от того, который не поддерживает, и хорошим, и плохим способами.
Дэвид Торнли
1
@ Steve314 - longjmp не является продолжением, хотя есть сходства. Продолжения сохраняют все состояние (все локальные, глобальные и стек). longjmp сохраняет указатель стека, поэтому, если вы выйдете за пределы области, где использовался setjmp, вы получите segfault, так как фрейм больше не существует. Я считаю, что есть также некоторые ограничения в переменных, которые он сохраняет.
dietbuddha
6

Связанная статья определенно делает это правильно о петлях N + 1/2 Дональда Кнута . Выражается в C / C ++ / Java:

for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}

Это полезно для чтения строк или символов из файла, проверки достижения EOF и последующей обработки. Я так привык видеть этот шаблон, for(;;)..if(..)break;что он идиоматичен для меня. (До того, как я прочитал статью Кнута, перепечатанную в книге « Грамотное программирование» , эта статья была «wtf?».)

Кнут предложил ключевые слова loop/while/repeat:

loop:
  S;
while C:
  T;
repeat

Где Sи Tявляются местозаполнителями для ряда нулевых или более операторов, и Cэто логическое условие. Если бы не было Sоператора, то это был бы цикл while, а если бы не было Tоператора, то это был бы цикл do.

Эту конструкцию можно обобщить, допуская ноль или более while Cпредложений, что делает ее идеальной для выражения бесконечных циклов, а затем некоторых более редких условий, которые потребуют двух проверок.

В той же статье Кнут предложил механизм сигнализации, который будет локальной версией исключения / перехвата (в качестве альтернативы использованию goto).

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


Обновление: я забыл упомянуть, что многие программисты на C / C ++ / Java обходят это, используя встроенное присваивание в условии while:

while ((c = getc(f)) != -1) {
   T;
}

Используя термины из конструкции Кнута, это допустимо, когда Sи Cможет быть объединено в одно выражение. Некоторые люди не хотят видеть внедренный назначение выше, в то время как другие ненавидят , чтобы увидеть breakв for (;;)выше. Но когда Sи Cне могут быть объединены, например, когда Sимеет несколько операторов, for (;;)единственная альтернатива без повторения кода. Другой вариант - просто продублировать Sкод:

S;
while (C) {
  T;
  S;
}

loop/while/repeatАльтернатива Кнута кажется намного лучше.

Макнейл
источник
Этот цикл пока повторяется очень похоже на repeat-untilцикл Паскаля .
Мейсон Уилер
@ Мейсон: Разница в том, что есть два места, где вы можете вставить выписки плюс ваше состояние, а не одно.
Макнейл
О, я вижу, что происходит. Да, это интересно ...
Мейсон Уилер
В ANSI Basic есть: do while ... loop untilи предварительное условие, и постусловие являются необязательными, и я (смутно) помню, что оба использовались в одном цикле. Для вашего среднего состояния есть Ада exit when ...;. Ключевым преимуществом if ... break;является то, что вы можете писать exit loopname when ...;для выхода из нескольких (но не обязательно всех) вложенных циклов одновременно. Возможно, чуть более заметен, чем этот разрыв, тоже.
Steve314
Забавная вещь. Ада имеет именно эту функцию.
Джон Р. Штром
6

В языке BCPL есть valueofвыражение, которое можно использовать для преобразования последовательности операторов в одно выражение:

foo(a, b, valueof {some series of statements; resultis v});

Где some series of statementsможет быть что угодно, и все valueofоценивает v.

Это может быть удобно в Java, когда вам нужно вычислить аргумент для вызова a this()или super()(который требует, чтобы ничего не происходило до этого). Конечно, вы можете просто написать отдельный метод, но это может быть неприятно, если вам нужно передать много локальных значений для контекста.

Если вы можете использовать finalпеременные, которые вам нужны, вы уже можете делать valueofв Java, используя анонимные внутренние классы:

foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());
Макнейл
источник
1
GCC имеет расширение для этого - ({ statement1; statement2; ...; result-expr; }). Я видел подобное и в других местах, но я не помню где. Вероятно, все скопировано из BCPL, хотя.
Steve314
6
unless(condition) {
  // ...
}

делает то же самое, что и:

if(!condition) {
  // ...
}

repeat {
  // ...
} until(condition)

делает то же самое, что и:

do {
  // ...
} while(!condition)
missingfaktor
источник
Возможно, вы захотите поехать в Лисп ...
Дюрос
1
Или Ruby, он имеет похожий синтаксис для unless.
Джош К
2
Выглядит вполне Перлиш. Существует несколько способов сделать это.
2
@ Steve314 Вы должны использовать неправильный стиль скобок. ;-)
Orbling
1
@ Orbling - совсем нет. Все остальные используют неправильный стиль скобок.
Steve314
5

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

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

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

Если два набора не имеют одинаковый размер, это может вызвать исключение, или вы могли бы иметь elseпосле цикла, чтобы сигнализировать о разнице в размерах.

Естественно, вы могли бы обобщить это для перехода в три или более списков.


Обновление: также полезно было бы делать декартово произведение между итерациями:

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

который был бы не более чем вложенными циклами:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

Я немного обеспокоен тем, что между двумя обозначениями, которые я привел здесь, есть разница O (n) и O (n ^ 2) в количестве пар, с изменением только одного символа.

Макнейл
источник
2
В Python есть zip и zip_longest, которые делают это.
pillmuncher
Круто, может быть, я недооцениваю Python и должен взглянуть на него через много лет. Это напоминает мне, иногда вы хотите и декартово произведение, эквивалентное вложенным циклам.
Макнейл
1
Оба эти случая в Scala: paste.pocoo.org/show/297429
missingfaktor
1
Относительно декартового произведения: опять же, в Python. for a, b, c in itertools.product(iter1, iter2, iter3):дает вам декартово произведение лениво оценивается. Что это? Вы тоже хотите перестановки и комбинации данного итератора? itertools.permutations, itertools.combinations.
Ааронастерлинг
1
Перспектива Haskell: используйте «zipWith» для первого случая и составьте список или монаду List для второго. Как и примеры Python / Scala, но более элегантные. :)
LennyProgrammers
5

Существует так называемая «петля Дейкстры» (также называемая «охраняемая петля Дейкстры»). Это было определено в «Охраняемом командном языке» (GCL) . Вы можете найти некоторую информацию о его синтаксисе и семантике в вышеупомянутой статье в Википедии в разделе 6 Повторение: сделайте .

В настоящее время я на самом деле знаю один язык программирования, который напрямую поддерживает эту структуру управления. Это Оберон-07 (PDF, 70 КБ). И он поддерживает «петлю Дейкстры» в форме оператора while. Взгляните на раздел 9.6. Хотя заявления в приведенном выше PDF.

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

PS Это копия моего SO ответа .

Дикая кошка
источник
Похоже, что модель проверки Spin также имеет эту конструкцию, с идентичной семантикой и в основном идентичным синтаксисом.
j_random_hacker
4

Выражения в стиле иконок со встроенным возвратом.

Python получает много преимуществ генератора иконок - и делает их лучше в целом, IMO. И в принципе обратный путь был просто своего рода исключением, но это была простота выражений, грубый эквивалент ...

x = (a / b) else c;

обрабатывать неудачные случаи, такие как деление на ноль.

Куда Icon сходила с ума - никаких операторов сравнения с логическим возвратом. Сравнения всегда либо удавались, либо вызывали обратное отслеживание, и была еще одна семантическая проблема, которую я сейчас отчаянно пытаюсь вспомнить ... ну, скажем так, это скорее подавлено, чем забыто.

Я всегда думал, что у них должно быть ifвыражение без какой-либо другой части - что-то if (condition, success-value)вроде этого, возвращаться назад, если условие возвращает false - и отбрасывать странные сравнения.

РЕДАКТИРОВАТЬ Я помню - очевидно, действительно Сравнение с двумя аргументами либо успешное, либо неудачное - оно не вычисляет новое значение для возврата. Поэтому , когда это удается, что делает его вернуть? Ответ - один из аргументов. Но если вы напишите a > b, какой логический аргумент для возврата - aили b? А что если b < aвместо этого написать ? Я думаю, что он всегда возвращал правильный аргумент, который имеет столько же смысла, как и все остальное, но обычно он мне показался неправильным аргументом.

Steve314
источник
4

Это просто общая идея и синтаксис:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

ТАКЖЕ условие всегда оценивается. ELSE работает как обычно.

Это работает для случая тоже. Вероятно, это хороший способ устранить оператор прерывания:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

можно прочитать как:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

Я не знаю, полезно ли это или просто читать, но это пример.

Maniero
источник
3

Продолжение Passing Style приходит на ум. Тогда, конечно, вы хотели бы также оптимизировать Tail Call .

pillmuncher
источник
1
Не большой поклонник этого, и я не верю, что это действительно «структура управления», а скорее строительный блок в функциональных языках и стиле программирования. Node.js, похоже, довольно зациклен на этом.
Джош К
1
Конечно, это контрольная структура. Это не просто ключевое слово типа 'if' или 'for', а шаблон для структурирования потока управления (следовательно, структуры управления). Он даже используется за кулисами многими компиляторами. И это не ограничивается FLs также. Вам нужны функции как объекты первого класса.
pillmuncher
1
В наши дни вы получаете оптимизацию хвостового вызова в C и C ++, но IMO упускает это. Дело в том , что она является оптимизация. В Схеме настоящий хвостовой вызов очевиден. В частности, в C ++ многие вещи могут означать, что ваш хвостовой вызов не является хвостовым вызовом. А переполнение стека означает, что ваше приложение не работает. IMO, должно быть что-то вроде goto return ...;оператора, делающего намерение явного вызова хвоста, поэтому, если компилятор не может сделать это итеративным, это ошибка.
Steve314
1
@Macneil - я точно знаю, что оптимизация хвостовых вызовов выполняется в GCC, Clang и Visual C ++. GCC имеет более сложные преобразования из рекурсии в итерацию, которые могут обрабатывать множество случаев, которые не являются хвостовой рекурсией. Но многое может пойти не так. Передайте указатель на локальную переменную в этом хвостовом вызове, и кадр стека не может быть удален, поскольку переменная должна поддерживаться в рабочем состоянии. В C ++ деструкторы локальных переменных обычно происходят после возврата вызова tail, то есть это вообще не вызов tail.
Steve314
1
@ Майк - это моя точка зрения. Если вы используете стиль рекурсивного кодирования, без хвостового вызова «оптимизация» ваш код может быть поврежден, поскольку переполнение стека является ошибкой. В C ++ это оптимизация - компилятору делать оптимизацию, так что вам не нужно это нормально, но вы не можете полагаться на них. Если вы хотите свободу писать в рекурсивном стиле, но не хотите беспокоиться о проблемах глубины стека, устранение хвостовых вызовов - это не оптимизация - это проблема правильности. Если рекурсия - лучший способ что-то кодировать, вы должны это сделать - не нужно беспокоиться о переполнении стека.
Steve314
3

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

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

Когда ветка вызывается, она немедленно возвращает дескриптор.

handle=foo(here, is, some, data)

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

handle.finished() //True if the execution is complete

Если результат запрашивается до завершения выполнения, основной поток просто ждет.

[result, storage]=handle.result()

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

AAAAAAAAAAAA
источник
Посмотрите на Cilk, это очень чистое и простое расширение C: en.wikipedia.org/wiki/Cilk . Я не знаю , если это имеет handle.finished()испытание, но spawnи syncвсе , что нужно для 90% параллельных задач программирования.
j_random_hacker
3
if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end

Блоки FIRST и THEN запускаются, если любое из 3 условий оценивается как true. Первый блок выполняется до условного блока, а затем - после выполнения условного блока.

Условная или окончательная запись ELSE после операторов FIRST и THEN не зависит от этих блоков.

Это может читаться как:

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return

Эти функции просто форма для чтения. Они не будут создавать возможности. Это больше похоже на госуб / возврат из Basic.

Полезность и читаемость как предмет обсуждения.

Maniero
источник
2

Иногда я пишу цикл, который должен сделать что-то другое во время первой итерации. Например, отображение тегов <th> вместо тегов <td>.

Я справляюсь с этой ситуацией с помощью логического флага. Что-то вроде этого:

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

Кажется глупым проверять значение firstна каждой итерации, когда она будет ложной в большинстве случаев.

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

Барри Браун
источник
Вопрос SO имеет аналогичную идею, но с оператором «then», который будет использоваться для значений. Таким образом, у вас, вероятно, нет дублированного кода. Напримерprint(out, first "<th>" then "<td>")
Макнейл
1
Лучше всего начать итерацию +1.
Джош К
1
Обычным случаем является циклическая обработка, например, перечисление элементов с разделителем-запятой. Строго говоря, if (!first) gimme-a-comma ();но это одно и то же. Однако у меня есть возражение - если вы оберните его должным образом, вы получите такие вещи, как метод объединения строк Python - как бы часто вам не требовался базовый шаблон, базовый цикл не нужно так часто переписывать.
Steve314
Как говорит Джош, конечно, вытащить первый элемент из цикла допустимо. В случае с разделителями-запятыми это означает дублирующийся код, но это может быть дублированный вызов функции. Лично я предпочитаю неэффективность if (!first), но микрооптимизаторы могут выдвигать возражения против предсказания ветвлений.
Steve314
1
@ Барри Браун: Развертывание 1-й итерации цикла может или не может быть быстрее, чем проверка логического флага. Я предсказываю, что приличный предсказатель ветвления в худшем случае будет неправильно прогнозировать первые 2 итерации :) Я бы предпочел использовать if (!first)и позволить оптимизирующему компилятору решить, достаточно ли мало тело цикла, чтобы развернуть и избавиться от него first- это чистый выигрыш.
j_random_hacker
1

[скопировано из моего собственного ответа на stackoverflow]


ignoring - игнорировать исключения, возникающие в определенном блоке кода.

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

С игнорирующей управляющей конструкцией вы можете написать ее более кратко и более наглядно, как:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[Scala предоставляет это (и многие другие конструкции управления обработкой исключений) в своей стандартной библиотеке в пакете util.control. ]

missingfaktor
источник
4
Исключения не следует игнорировать.
Джош К
1
За исключением того, что в контексте исключение не может быть ошибкой.
Steve314
1
@Josh, @Steve: бывают случаи, когда вы хотите игнорировать исключения. Посмотрите эту ветку для некоторых таких случаев.
фактор
Исключением является предупреждение о том, что что-то может быть не так. Пустой try..catchблок - это одно; это заставляет вас признать ошибку и сознательно игнорировать ее; в то время как бросание кусков кода в глобальное игнорирование может привести к проблемам при создании этих исключений, а также к плохим привычкам программирования.
Джош К
@ Джош - Просто удалил два комментария, потому что я не думал прямо - но надежды на это велики. Если это утверждение является глобальным, я, вероятно, согласен - но для меня это выглядит как блочная структура. IOW это как tryблок, за исключением того, что он перечисляет исключения, которые он перехватывает и игнорирует сразу, а не позже. Это может даже стать преимуществом читабельности - например, дать читателю понять, что отсутствующий файл не является ошибкой даже до того, как он прочитает открытый вызов.
Steve314
1

Вместо того:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

Сделайте это на Python, а теперь и на C #:

action = val2func[myEnum]
action()

Scala имеет много новых функций.

Наконец, языки, такие как Clojure, могут быть расширены для обеспечения дополнительной функциональности.

работа
источник
1
С тоже может это сделать. И Паскаль. Вероятно, все эти старые языки 70-х / 80-х / 90-х годов. Массив функций становится массивом указателей на функции, но это не составляет большого труда. Когда становится проще, когда у вас есть анонимные функции - вы знаете, как в Lisp, ML, ...
Steve314
Steve314 - коррекция - это пример словаря, который отображает любое значение в функцию. Здесь вещи становятся немного чище, чем большинство вещей 70-х / 80-х / 90-х годов.
Работа
1

У меня есть две идеи.

Часто я обнаруживаю, что повторяюсь в catchблоках. Этому можно помочь с помощью извлечения методов, но это может вызвать ненужный беспорядок, если методы очень короткие или иным образом не заслуживают метода. Итак, было бы неплохо вложить catchблоки:

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

В веб-программировании я часто обнаруживаю, что часто делаю что-то подобное (это не реальный пример, поэтому не анализируйте вымышленные случаи):

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

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

var a = getAFromLocation1() || getAFromLocation2() || default;

Мне действительно нравится, как это выглядит, и я хотел бы, чтобы больше языков, особенно некоторые на стороне сервера, имели поддержку для этого. (PHP может вычислить что-либо как условие, но преобразует все условное выражение в логическое значение вместо сохранения значения. Я не знаю насчет Python или Ruby.) Это может стать громоздким после трех случаев или около того, но если у вас есть больше чем в трех случаях, вы также можете иметь плохой дизайн программного обеспечения.

Николь
источник
Python делает что-то вроде вашего || оценки, но когда он, наконец, получил свой x if c else yсинтаксис условных выражений , главная причина этого состояла в том, что многие выражения использовали эту семантику для ||и &&были слегка ошибочными. IIRC распространенным случаем было значение (например, ноль), которое было допустимо для приложения, которое обрабатывается как false, и, таким образом, отбрасывалось, так что вместо него использовался неправильный запасной вариант. Однако - см. Мой ответ WRT Язык программирования Icon, который может иметь такие выражения, как get1() else get2() else default.
Steve314
1

Обобщенный коммутатор сказал выше:

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

В Хаскеле:

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs

источник
0

В C # я хотел бы использовать простые switch () { ... }, но расширяемые с такими выражениями:

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

И так далее. То же самое с числами или другими типами (что поддерживает IComparable, IConvertible...)

Это может сделать мой код более лаконичным и читабельным.

гениальность
источник
Проваливать дела - это известное зло, и я, как правило, без него. И прыжки слишком GOTOish для любого вменяемого программирования. Но наличие выражений и нестатики в этом случае было бы прекрасным дополнением.
CodexArcanum
0

Это интересный вопрос, как сказал @Macneil.

Моя любимая необычная структура управления, которую я (смиренный кашель) обнаружил, это дифференциальное исполнение .

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

Обычно я реализую это с помощью макросов на C или C ++. В C # я должен делать это с помощью расширений рук. Это боль, но это работает.

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

Майк Данлавей
источник
0

«Традиционные» структуры управления, такие forкак управление рабочим человеком, подчинение его коррупционным идеологиям правящей капиталистической элиты. Вот почему я ph0rвместо этого использую альтернативные структуры управления . Это как for, но более радикально: вы не поймаете ph0rносить костюм и галстук, извергая некоторые корпоративные BS. ph0rДержи это по-настоящему, чувак.

Бороться с властью!

j_random_hacker
источник
0

Самый forпростой цикл

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
Gulshan
источник