Чи корисні продовження першого класу в сучасних об'єктно-орієнтованих мовах програмування?


10

Продовження є надзвичайно корисними у функціональних мовах програмування (наприклад, Contмонада в Haskell), оскільки вони дозволяють просте і регулярне позначення коду імперативного стилю. Вони також корисні для деяких старих імперативних мов, оскільки їх можна використовувати для реалізації функцій, які відсутні у мові (наприклад, винятки, супроводи, зелені нитки). Але для сучасного об'єктно-орієнтованої мови програмування з підтримкою вбудованої в цих функції, які аргументи чи для також додати підтримку для першого класу продовжень (будь то більш сучасним стиль з роздільниками resetі shiftчи схема типу call-with-current-continuation)?

Чи є аргументи проти додавання підтримки, окрім продуктивності та складності впровадження?

Відповіді:


15

Давайте відповімо на це Ерік Ліпперт:

Очевидне питання на даний момент: якщо CPS настільки приголомшливий, то чому б ми не використовували його весь час? Чому більшість професійних розробників ніколи не чули про це, або ж ті, хто є, вважають це тим, що роблять лише ті шалені програмісти програми?

Перш за все, більшості людей, які звикли думати про підпрограми, цикли, пробування, нарешті, і так далі, важко міркувати про те, як таким чином делегати використовуються для управління потоком. Я зараз переглядаю свої нотатки про CPS від CS442 і бачу, що в 1995 році я записав профвоту: "З продовженням вам доведеться якось стати на голову і витягнути себе назовні". Професор Даґган (*) абсолютно вірно сказав це. Нагадаємо, пару днів тому, що наш крихітний приклад трансформації CPS виразу C # M (B ()? C (): D ()) включав чотири лямбда. Не всі добре читають код, який використовує функції вищого порядку. Це накладає великий пізнавальний тягар.

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

У наступній статті він пояснює, наскільки асинхронність та продовження точно рівнозначні один одному, і продемонструє демонстрацію прийняття простої (але блокуючої) синхронної мережевої операції та переписування її в асинхронному стилі, обов'язково охоплюючи все приховане gotchas, які потрібно прикрити, щоб виправити це. Це перетворюється на масовий безлад коду. Його підсумок в кінці:

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

Пам'ятаєте, що я говорив про плюси та мінуси CPS?

  • PRO: Довільно складні та цікаві контрольні потоки можна побудувати з простих частин - перевірити.
  • CON: Змінення потоку управління через продовження важко читати і важко міркувати - перевірити.
  • КОН: Код, який представляє механізми управління потоком, повністю переповнює значення коду - перевірка.
  • КОН: Перетворення звичайного потоку управління кодом в CPS - це те, в чому компілятори хороші, і майже ніхто інший - перевірка.

Це не якась інтелектуальна вправа. Справжні люди закінчують писати код, морально еквівалентний вище, ніж час, коли вони мають справу з асинхронією. І, за іронією долі, навіть коли процесори стають швидшими та дешевшими, ми витрачаємо все більше свого часу на очікування речей, не пов'язаних з процесором. У багатьох програмах значна частина часу витрачається на те, що процесор прив’язаний до нуля в очікуванні, щоб мережеві пакети здійснили поїздку з Англії до Японії і назад, або для того, щоб крутитися дисками, або що завгодно.

І я навіть не говорив про те, що станеться, якщо ви хочете далі складати асинхронні операції. Припустимо, ви хочете зробити ArchiveDocuments асинхронною операцією, яка приймає делегата. Тепер весь код, який викликає його, повинен бути записаний і в CPS. Тінь просто поширюється.

Правильне забезпечення асинхронної логіки важливо, це буде лише важливіше в майбутньому, і інструменти, які ми вам надали, змушують вас "стояти на голові і перевертатися назовні", як мудро сказав професор Даґган.

Стиль передачі продовження є потужним, так, але, мабуть, є кращий спосіб використовувати цю потужність, ніж наведений вище код.

Обидві статті, а також наступна серія про нову функцію мови C #, яка переміщує весь цей безлад у компілятор і дозволяє записати свій код як звичайний потік управління спеціальним ключовим словом для позначення певних частин як асинхронних, добре варто прочитати, навіть якщо ви ' ви не розробник C #. Я це не так, але це було все ще досить освічуючим досвідом, коли я вперше натрапив на нього.


5
Варто зазначити, що якщо ваша мова підтримує розширення синтаксису на зразок макросів, то продовження стає набагато кориснішим, оскільки ви можете приховати механізми реалізації різних видів цікавого керуючого потоку всередині розширень синтаксису. В основному, як працює "очікування", це просто визначено мовою, оскільки C # не надає інструментів для самостійного визначення цих видів розширень синтаксису.
Джек

Хороша стаття, хоча зазначу, що CPS та продовження першого класу - це не одне і те саме (CPS - це те, що ви робите мовою, не підтримуючи продовження, коли виявите, що вам це потрібно). Здається, що C # йде вниз по тому ж маршруту, про який я думав (хоча я не можу вирішити, чи хочу я автоматизувати перетворення шин на CPS або реалізувати повнорозмірне продовження копіювання стека з обмеженим продовженням).
Жуль

@Jack - це саме те, що я зараз розглядаю: мова, яку я розробляю, має макрокоманду, яка може підтримувати перетворення CPS автоматично. Але повне місцеве продовження може дати кращі результати ... питання полягає в тому, як часто вони будуть використовуватися в критичних ситуаціях?
Жуль
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.