Що нового у світі програмування
Повна версія
Що нового у світі програмування
[Перевод на русский язык — в конце материала.]
Напевно не існує області знань, якій не пророкують «теплову смерть» від відсутності розвитку. Програмування не є виключенням: досить часто можна почути що все, що можна було придумати в програмуванні вже є у 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 задач), еще два слота ожидают ваших тем.