Що нового у світі програмування

Автор або джерело: Ruslan Shevchenko

Першоджерело

програмування

Повна версія

Що нового у світі програмування

[Перевод на русский язык — в конце материала.]

Напевно не існує області знань, якій не пророкують «теплову смерть» від відсутності розвитку. Програмування не є виключенням: досить часто можна почути що все, що можна було придумати в програмуванні вже є у Lisp/Fortran/Smalltalk (підкреслити вибране) і нічого принципово нового з тих часів так і не створено

Мої улюблені контрприклади: прийоми програмування, що з`явились порівняно недавно, при цьому досить прості та з досить широким застосуванням, це

  • відкладені блоки в послідовності виконання
  • переміщення компіляції (staging)

ілюстрація до процесу розвитку індустрії програмування взята з блогу Григорія Громова: abcdefgh.livejournal.com/1461405.html

Давайте подивимось на них детальніше:

Відкладені блоки в послідовності виконання команд

Приклад — конструкція scope в D або defer в Go. Основна ідея полягає в тому, що така одиниця комп’ютерної мови як блок виконання, розглядається не просто як послідовність команд з можливістю аварійного виходу за допомогою генерування виключень, але як більш складна конструкція, з кошиком куди в процесі виконання можна додавати команди, які будуть виконуватися згодом, після завершення основного блоку.

Таке структурування часто є більш зручним ніж традиційна обробка виключних ситуацій, внаслідок простішої композиції. Класичний приклад — нехай в нас є дві послідовні операції що потребують відновлення стану після збою:

Якщо ми захочемо додати сюди третю операцію, треба буде її вставляти у як ще один рівень вкладеності try/catch блоків. Якщо ми захочемо, щоб in та out були на одному рівні вкладеності, то виникне необхідність дублювання коду:

На D в такій ситуації можна написати наступне:

Тобто блок коду, маркований як scope(exit) буде виконуватися при виході з блоку (також в D існує scope(failure) та scope(success), що маркують виконання тільки у випадку відповідно неуспішного або успішного завершення блоку.

В Go приблизно з цією-ж метою додана конструкція defer:

Команди, що задані в defer будуть виконані наприкінці виходу із функції.

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

Для подальшого знайомства з темою рекомендую

  • подивитись лекцію Александреску: channel9.msdn.com/...​-Successful-Features-of-D , де є більш детальній опис та порівняння цієї технології з автоматичним менеджментом ресурсів у мовах подібних до С++,
  • також може бути цікава наступна стаття blog.golang.org/...​er-panic-and-recover.html про обробку помилок в go.

Staging

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

Тобто наступний вираз:

 
for(  s <- students if (s.course == 4) ) yield  s.name

може, в залежності від типу students компілюватися як в цикл, що проходить по колекції students, так і в щось подібне до sql запиту:

  select s.name from students s where s.course == 4

або виклику javascript функції:

Як це працює:

  • При компіляції мовні конструкції «віртуалізуються», тобто наведений вище приклад компілюється в щось подібне до students.filter(s = > s.course == 4).map(s => s.name), а if (x) y else z в щось подібне до __ifThen(x,y,z) , де _filter , map , __ifThen_ — стандартні функції або макроси.

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

Ті з читачів, кто працює з C#, напевно впізнали LINQ; в scala деяке узагальнення цього підходу буде використовуватись як для роботи з базами даних, так і в ряді бібліотек (від компіляції javascript до хостингу обчислень на графічному процесорі)

Для подальшого знайомства з темою рекомендую

  • подивитись виступ Наді Амін (про побдуову в scala внутрішнього DSL для генерації Javascript: skillsmatter.com/...​script-embedded-dsl-scala
  • та прочитати статтю Тьярка Ромпфа та Мартина Одескі:
    ‘Lightweight Modular Staging: A Pragmatic Approach to Runtime Code Generation and Compiled DSLs’ infoscience.epfl.ch/...​47/files/gpce63-rompf.pdf де показано повний приклад побудови staging компіляції для невеликого внутрішнього DSL

Розкажіть мені щось

А які техніки програмування ви відкрили для себе за останні декілька років ? Якщо хочете доповісти щось цікаве — зв’яжіться зі мною та приходьте на Kyiv::fprog, що відбудеться 21-го липня 14:00 — 18:00 у конференц-залі кубік- центру на Шолуденка 3.
(реєстрація: dou.ua/calendar/2040 ). Приміщення спонсує strikead (мій поточний роботодавець, до речі організація з R&D центром у Києві, де активно використовується функціональний підхід), а наповнення у форматі міні-баркампу організують різні цікаві люди — точно буде секція про Erlang яку буде вести Лев Валкін (приводом для організації події став його приїзд до Києва) можливо також з перших рук можна буде почути також про використання Erlang в strikead від Олега Смірнова, обіцяє бути цікавою секція про LISP-похідні (Всеволод Демкін розповість про те, чому вам може не підійти clojure та як в Grammarly використовують комбінацію Java та Common Lisp для AI задач), ще два слота чекають на ваші теми.

Перевод на русский язык

Каждой дисциплине время от времени пророчат тепловую смерть: программирование не исключение. Нередко можно услышать, что все, что можно было придумать уже придумано и есть в Fortrane / Lisp-e / Smalltalk-e (нужное подчеркнуть).

Два моих любимых контрпримера: техники программирования, появившиеся сравнительно недавно, при этом сравнительно простые и широко применяющихся в индустрии — это

  • структурирование последовательности исполнения
  • перемещение цели компиляции (staging)

иллюстрация к процессу развития индустрии программирования взята из блога Григория Громова: abcdefgh.livejournal.com/1461405.html

Расскажем о них подробнее:

Структурированная последовательность исполнения.

Пример — это конструкция scopes в D или defer в Go.

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

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

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

На D это же пишется как:

То есть блок кода, помеченный scope(exit) выполняется при выходе из блока. (В D определены еще scope(failure) — выполняется при неудачном завершении и scope(success) — при удачном).

На go приблизительно для этой-же цели может использоваться конструкция deferred:

Блоки кода, помеченные как deferred, выполняются при выходе из функции

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

Для дальнейшего ознакомления с темой рекомендую

  • видеозапись выступления Александреску на Channel 9: channel9.msdn.com/...​-Successful-Features-of-D где он описывает эту конструкцию в D и показывает как она соотносится с ARM (Automatic Resource Management) подходом, принятом в языках типа С++
  • cтатью про восстановление после ошибок в Go. golang.org/...​/defer_panic_recover.html

Staging

[На русский правильнее всего, наверное, перевести как «перемещение компиляции»]. Это технология, позволяющая придать одним и тем же выражением разный смысл — то есть буквально переориентировать компилятор на другой язык в определенном контексте

for(  s <- students if (s.course == 4) ) yield  s.name

может (в зависимости от типов данных students) скомпилироваться как в цикл, который проходит по коллекции students, так и в нечто вроде sql запроса:

   
  “select s.name from students s where s.course == 4”

или javascript выражения

Как это работает:

  • конструкции языка виртуализируются: то есть приведенное выше выражение for компилируется в нечто вроде: students.filter(s = > s.course == 4).map(s => s.name) , а выражение if (x) y else z в нечто вроде __ifThen(x,y,z)_

  • Для типов со стандартной семантикой компилятор использует встроенную реализацию виртуализируемых функций (или макросов, как правило вместе с inline оптимизациями, убирающими эту прослойку), а для типов определенных пользователем — подставляет определенные пользователем реализации

Те кто работает с С# вероятно узнали тут LINQ, в scala некоторое обобщение данного подхода будет применяться как и для работы с БД (slick) так и в целом ряде библиотек — от генерации javascript до хостинга вычислений на графическом процессоре

Рекомендую

  • посмотреть лекцию Нади Амин про встравание в scala DSL для генерации javascript: skillsmatter.com/...​script-embedded-dsl-scala
  • и статью Тьярка Ромпфа и Мартина Одескі:
    ‘Lightweight Modular Staging: A Pragmatic Approach to Runtime Code Generation and Compiled DSLs’ infoscience.epfl.ch/...​47/files/gpce63-rompf.pdf где строится полный пример небольшого встроенного языка со staging компиляцией.

Расскажите что-то

А какие техники вы открыли для себя в последнее время ? Если хотите рассказать и послушать что нового — приходите на встречу Kiev::fprog в Киеве 21-го июля с 14:00 до 18:00 в конференц-зале Кубик-центра на Шолуденко 3 (dou.ua/calendar/2040 — регистрация). Помещение спонсирует strikead (мой текущий работодатель, кстати, организация с R&D центром в Киеве, где активно используется функциональний подход), а наполнение в формате мини-баркампа организуют разные интересные люди — точно будет секция про Erlang, котороую будет вести Лев Валкин (вобще-то поводом для организации события стал его приезд в Киев) также возможно из первых рук можно будет также услышать про использование Erlang в strikead от Олега Смирнова, обещает быть интересной секция про производные Lisp-а: (Всеволод Демкин расскажет про то, почему вам может не подойти clojure и как в Grammarly используют комбинацию Java и Common Lisp для AI задач), еще два слота ожидают ваших тем.