Які корисні альтернативні структури управління ви знаєте? [зачинено]


12

Подібне запитання було закрито на SO.

Іноді, коли ми програмуємо, ми виявляємо, що якась конкретна структура управління була б нам дуже корисною, але вона безпосередньо не доступна на нашій мові програмування.

Які альтернативні структури управління, на вашу думку, є корисним способом організації обчислень?

Мета полягає в тому, щоб отримати нові способи мислення про структурування коду, щоб покращити чування та міркування.

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

Відповіді мають дати ідеї для нової мови програмування або покращення фактичної мови.

Подумайте про це як мозковий штурм, тому опублікуйте те, що, на вашу думку, є шаленою ідеєю, але це може бути життєздатним у певному сценарії.

Йдеться про імперативне програмування.


1
Чому це питання має стосуватися "імперативного програмування"?
зниклий фактор

@missingfaktor: Оскільки структури управління стосуються обов'язкового програмування. Звичайно, деякі проблеми можна вирішити функціональним підходом або іншим способом, але інші парадигми не ставлять керуючі структури в центр розвитку. Але все одно ти можеш бути творчим.
Маньєро

3
Що ж, я збирався поділитися шаблоном зіставлення з гвардійцями, оскільки вони є загальнішими, ніж заяви про випадки та «Ікс-тени», але якщо це зона не FP, я думаю, це просто більше узгодження шаблону для решти нас!
CodexArcanum

@CodexArcanum: Ну, узгодження шаблонів - це конструкція, дуже схожа на імперативні конструкції. Дійсно, узгодження шаблону саме по собі є альтернативою необхідним структурам управління. Не соромтесь ;-)
Маньєро

Дивлячись на всі відповіді, я щасливий, що жодна з пропозицій не існує в реальному житті (і, сподіваюся, ніколи не буде). Вибачте :)
серг

Відповіді:


14

Гаразд, це цікаве питання.

Я також хотів би мати загальний elseчас і цикл, коли умова не відповідає дійсності на першому тесті:

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

Це дозволяє уникнути незручного перерахунку умови або збереження його у змінній.


У Python це є.
Баррі Браун

Гей! Нарешті вигадливий вибір Python, з яким я згоден! ;-)
Макнейл

5
Ні. Інше застереження в Python for / while циклів виконується, якщо цикл закінчується нормальним, а значить, цикл не припиняється через операцію break або return або виняток. Клас ін для циклів виконується після того, як буде вичерпана послідовність елементів, що перебуває в циклі, і в той час, коли цикли виконуються після того, як умова циклу вперше оцінюється на False.
пігулка

4
Існує запит додати while ... elseконструкцію так, як Macneil описує її до PHP. Я думаю, що це чудова ідея, оскільки "ось результати / результатів не було" є досить поширеною фразою у веб-додатках.
Дін Хардінг

1
@SnOrfus: Він хоче блок коду (окремо від блоку циклу), який виконується ТІЛЬКИ, якщо умова доки ніколи не виконується. Do-Хоча виконує блок коду циклу (а не якийсь окремий блок) один раз, незалежно від умовного в той час.
Легіон

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.

Розширюваний, узагальнений синтаксис конструкції управління потоком в імперативній мові був би досить корисним і розважальним. Поки це не з’явиться, я думаю, я просто використаю Lisp або щось подібне.


5
Не корисно, заплутано. Не розважально, повільно.
Джош К

2
@Josh K: Так, ти маєш рацію. Що, ти думав, я не погоджуюся? Ця відповідь кусає мову, щоб не сміятися.
Джон Перді

Якщо це мав на увазі іронічно, це, безумовно, вдалося!
Джош К

11
+1 Сміяв мене. Для виконання коду між ітераціями потрібен пункт "між".
Баррі Браун

1
+1, але це також потрібно seventh { ... }.
j_random_hacker

7

Структури управління як функції.

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

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

Це, звичайно, менше стосується конкретної структури управління і більше стосується того, як ви бачите структури управління в цілому, мета керуючих структур.


2
Продовження є важкою концепцією для мови, і є вагомі причини для того, щоб залишити їх з багатьох мов.
Девід Торнлі

Я не згоден; маючи for, if, elseі whileяк функція змушує мене зробити висновок , що параметри цих функцій повинні бути виконані ліниво, щоб вести себе так само , як оригінальні конструкти. Мати можливість робити ліниве виконання було б непогано.
Учень доктора Вілі

1
@David: Тільки тому, що вони є, це не означає, що ви повинні їх використовувати. Регулярні програмісти можуть використовувати те, до чого звикли return, винятки тощо. Але зараз експерт-програміст має потужний додатковий інструмент у своєму наборі інструментів, якщо виникає потреба. Крім того, мови ІМХО не слід "скидати". Мови повинні мати можливість підтримувати розширений досвід та зростання знань про КС.
дієтабудда

1
@dietbuddha: (продовження) Я не кажу, що продовження є поганим, я кажу, що вони важкі, і тому, що їх можна використовувати, це може вплинути на мову, щось подібне до винятків. Крім того, продовження роботи, ймовірно, може призвести до змін у тому, як люди використовують мову, знову ж таки як винятки в C ++. Мова, яка підтримує продовження, буде відрізнятися від мови, яка не є, і в хорошому, і в поганому плані.
Девід Торнлі

1
@ Steve314 - longjmp не є продовженням, хоча є схожість. Продовження зберігають всю державу (усі локальні, глобальні та стек). longjmp зберігає вказівник стека, тож якщо ви уникнете межі області, де використовувався setjmp, ви отримаєте segfault, оскільки кадру більше не існує. Я вважаю, що є також деякі обмеження в змінних, які вони зберігають.
дієтабудда

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заяви, то це був би цикл, а якщо не було, 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петля Паскаля .
Мейсон Уілер

@ Мейсон: Різниця в тому, що ви можете вставити заяви плюс ваш стан, а не два.
Macneil

О, я бачу, що відбувається. Так, це цікаво ...
Мейсон Уілер

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, коли вам потрібно обчислити аргумент для виклику this()або super()(що вимагає, щоб перед ним нічого не відбувалося). Звичайно, ви можете просто написати окремий метод, але це може бути болем, якщо вам потрібно передати багато локальних значень для контексту.

Якщо ви можете використовувати finalдля необхідних змінних, ви вже можете робити valueofJava на анонімних внутрішніх класах:

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)

Можливо, ви захочете поїхати в Лісп ...
duros

1
Або Ruby, він має подібний синтаксис для unless.
Джош К

2
Виглядає досить Перліш. Існує більше ніж один спосіб зробити це.

2
@ Steve314 Ви повинні використовувати неправильний стиль дужки. ;-)
Включення

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) і O (n ^ 2), лише зміна одного символу.


2
У Python є zip та zip_lo most, які роблять це.
пігулка

Круто, можливо, я недооцінюю Python і мушу дати йому другий вигляд через багато років. Це нагадує, що іноді ви хочете і декартового продукту, еквівалента вкладеного циклу.
Macneil

1
Обидва ці випадки в Scala: paste.pocoo.org/show/297429
missingfaktor

1
Що стосується декартового продукту: знову ж таки, Python має його. for a, b, c in itertools.product(iter1, iter2, iter3):дає вам декартовий продукт ліниво оцінений. Що це? Ви також хочете перестановки та комбінації заданого ітератора? itertools.permutations, itertools.combinations.
aaronasterling

1
Перспектива Haskell: використовуйте "zipWith" для першого розуміння випадку та списку або монаду List для другого. Як і приклади Python / Scala, але більш елегантні. :)
LennyProgrammers

5

Існує так звана «петля Дейкстри» (також її називають «Охоронна петля Діжкстри»). Це було визначено мовою охоронних команд (GCL) . Ви можете ознайомитись із синтаксисом та семантикою інформації про це у вищенаведеній статті Вікіпедії у розділі 6 Повторення: виконайте .

Сьогодні я фактично знаю одну мову програмування, яка безпосередньо підтримує цю структуру управління. Це Oberon-07 (PDF, 70 KB). І він підтримує "цикл Dijkstra" у формі оператора 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 отримує багато переваг генератора Icon - і робить їх краще, загалом, IMO. І в принципі, зворотний трек був просто винятком винятком, але це була простота виразів, грубо еквівалентна ...

x = (a / b) else c;

обробляти випадки відмов, як поділ на нуль.

Куди пішов Icon - немає булевих операторів порівняння. Порівняння завжди або вдалося, або викликало відхилення, і було якесь інше семантичне питання, яке я зараз відчайдушно намагаюсь згадати про це ... ну, скажімо, це, мабуть, більше репресовано, ніж забуте.

Я завжди думав, що вони повинні мати ifвираз із жодною іншою частиною - if (condition, success-value)такою річчю, зворотним відстеженням, якщо стан повертається неправдивим - і відмовитись від дивних порівнянь.

EDIT Я пам’ятаю - справді очевидно. Порівняння з двома аргументами або вдале, або невдале - воно не обчислює нове значення для повернення. Тому , коли це вдається, що робить його повернути? Відповідь - один з аргументів. Але якщо ви пишете a > b, який логічний аргумент повернути - aчи b? А що робити, якщо писати b < aзамість цього? Я думаю, що це завжди повертав правильний аргумент, який має стільки ж сенсу, як і все, але це все одно зазвичай здавалося мені неправильним аргументом.


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

Я не знаю, чи це корисно чи просто читати, але це приклад.


3

Продовження Стиль проходження спадає на думку. Тоді, звичайно, ви хочете також провести оптимізацію дзвінків Tail .


1
Це не великий шанувальник цього, і я не вірю, що це дійсно "структура управління", а скоріше будівельний блок у функціональних мовах та стилі програмування. Схоже, Node.js досить зачеплений за нього.
Джош К

1
Звичайно, це структура управління. Це просто не те, що має ключове слово типу "якщо" або "за", а як зразок для структури управління потоком (отже, структурою управління). Його навіть використовують за лаштунками багато компіляторів. І це також не обмежується FL. Вам потрібні функції як об'єкти першого класу.
пігулка

1
Ці дні ви отримуєте оптимізацію хвостових дзвінків в C і C ++, але IMO це не вистачає суті. Справа в тому , що вона є оптимізація. У схемі очевидний справжній хвіст. Особливо в C ++ багато речей можуть означати, що ваш дзвінок не є хвостиком. А переповнення стека означає, що ваша програма зламана. IMO, повинно бути щось на кшталт goto return ...;заяви, що робить намір зробити хвіст викликом явним, тому якщо компілятор не може зробити його ітераційним, це помилка.
Steve314

1
@Macneil - про що я точно знаю, оптимізація хвостових викликів проводиться в GCC, Clang та Visual C ++. GCC має більш складні перетворення від рекурсії до ітерації, які можуть обробляти ряд випадків, які не мають хвостової рекурсії. Але багато може піти не так. Передайте вказівник на локальну змінну у цьому виклику хвоста, і кадр стека неможливо усунути, оскільки змінну потрібно підтримувати в живих. У C ++ локальні деструктори змінних, як правило, трапляються після повернення "хвостового" дзвінка, тобто це зовсім не хвостовий виклик.
Steve314

1
@Mike - ось моя суть. Якщо ви використовуєте рекурсивний стиль кодування, без хвостового виклику "оптимізація" ваш код потенційно порушений, оскільки переповнення стека є помилкою. У 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()

Це не охопить більш просунуті багатопотокові сценарії, а скоріше забезпечить легко доступний спосіб початку використання декількох ядер.


Погляньте на 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 умовностей оцінено як істинне. ПЕРШИЙ блок працює до умовного блоку, а потім - після запуску умовного блоку.

Умовне або остаточне записування 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

Ці функції - це просто форма для читання. Вони не створили б сферу застосування. Це більше схоже на gosub / return з Basic.

Корисність та читаність як предмет обговорення.


2

Іноді мені здається, що я пишу цикл, який повинен зробити щось інше під час першої ітерації. Наприклад, відображення тегів <th> замість тегів <td>.

Я обробляю цю ситуацію булевим прапором. Щось на зразок цього:

first = true

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

Здається, нерозумно перевіряти значення firstкожної ітерації, коли вона буде помилковою більшу частину часу.

Я хотів би мати варіант циклу, щоб вказати інше тіло циклу під час першої ітерації. Не було б потреби в окремій змінній. Скомпільований код також не знадобиться, тому що згенерований код матиме два тіла: одне для першої ітерації та одне для решти.


Питання SO має схожу ідею, але з оператором "тоді", який слід використовувати для значень. Таким чином, у вас, ймовірно, немає дублюваного коду. Напр.print(out, first "<th>" then "<td>")
Макнейл

1
Кращий спосіб - або запустити ітерацію +1.
Джош К

1
Поширений випадок - це циклічність між обробкою, наприклад, перерахування елементів із роздільником коми. Строго, це if (!first) gimme-a-comma ();, але майже те саме. Хоча у мене виникне заперечення - якщо ви його завершите належним чином, ви закінчитесь такими речами, як метод з'єднання рядків Python - однак часто вам потрібен основний зразок, нижній цикл не повинен переписуватися так часто.
Steve314

Як каже Джош, звичайно, витягнення першого предмета з циклу є дійсним. У випадку розділення комами це означає, що він повторює код, але це може бути дублюваний виклик функції. Особисто я вважаю за краще неефективність if (!first), але мікрооптимізатори можуть викликати заперечення щодо галузевого прогнозування.
Steve314

1
@Barry Brown: Розгортання 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. ]


4
Винятки не слід ігнорувати.
Джош К

1
За винятком того, що в контексті виняток може не бути помилкою.
Steve314

1
@Josh, @Steve: Є випадки, коли ви хочете ігнорувати винятки. Дивіться цю тему для деяких таких випадків.
зниклий фактор

Виняток - попередження про те, що щось може бути не так. Порожній try..catchблок - це одне; це змушує вас визнати помилку і свідомо її ігнорувати; в той час як викидання фрагментів коду під глобальним ігноруванням може призвести до проблем, коли ці винятки кидаються, а також призведе до поганих звичок програмування.
Josh K

@Josh - Просто видалили два коментарі, тому що я не думав прямо - але сподівання є великими для цього. Якщо це твердження є глобальним, я, мабуть, погоджуюся - але мені це виглядає як блокова структура. IOW це як tryблок, за винятком того, що він перераховує винятки, які він ловить і ігнорує вперед, замість того, щоб пізніше. Це навіть може бути перевагою читабельності - наприклад, повідомляти читачеві, що файл, що відсутній, не є помилкою ще до того, як вони прочитали відкритий виклик.
Стів314

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();
 }

У Haskell:

  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зберігає це реально, чоловіче.

Боріться за владу!


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
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.