Системы эффектов
Недавно послушал выпуск Подлодки про "Системы эффектов в языках программирования" и решил поделиться некоторыми рандомными рассуждениями на эту тему.
"Окраска" функций
"Окраской" функций называется некоторая декларация эффектов, содержащихся в функции.
В JavaScript есть 2 варианта "окраски" функций:
-
-
Fun fact: эти 2 варианта можно скомбинировать, чтобы получить AsyncIterator, который можно перебирать оператором for await...of.
В языке Nim система эффектов позволяет окрашивать функции любыми эффектами, что выглядит весьма любопытно (на самом деле существует ещё множество языков с такой возможностью, но почему-то мне сразу вспомнился именно Nim).
Обработка исключений
В Java есть оператор throws, позволяющий "окрасить" функцию эффектом выброса определённого типа исключения и на этапе сборки удостовериться, что эти исключения обработаны.
JavaScript/TypeScript не позволяет типизировать исключения (разве что задокументировать их с помощью JSDoc или TSDoc), но теоретически эту проблему можно решить знаменитой монадой Either.
Чистота функций
Бандлеры используют аннотацию
В самом JavaScript нет языкового средства для выражения чистоты функции — то есть отсутствия в ней эффектов, хотя было бы классно использовать это знание, например, для исполнения кода во время сборки (как, например, c babel-plugin-macros).
Недавно послушал выпуск Подлодки про "Системы эффектов в языках программирования" и решил поделиться некоторыми рандомными рассуждениями на эту тему.
"Окраска" функций
"Окраской" функций называется некоторая декларация эффектов, содержащихся в функции.
В JavaScript есть 2 варианта "окраски" функций:
-
async
— обозначает, что функция асинхронная и позволяет использовать внутри неё оператор await
-
*
— обозначает, что функция является генератором и позволяет использовать внутри неё оператор yield
Fun fact: эти 2 варианта можно скомбинировать, чтобы получить AsyncIterator, который можно перебирать оператором for await...of.
В языке Nim система эффектов позволяет окрашивать функции любыми эффектами, что выглядит весьма любопытно (на самом деле существует ещё множество языков с такой возможностью, но почему-то мне сразу вспомнился именно Nim).
Обработка исключений
В Java есть оператор throws, позволяющий "окрасить" функцию эффектом выброса определённого типа исключения и на этапе сборки удостовериться, что эти исключения обработаны.
JavaScript/TypeScript не позволяет типизировать исключения (разве что задокументировать их с помощью JSDoc или TSDoc), но теоретически эту проблему можно решить знаменитой монадой Either.
Чистота функций
Бандлеры используют аннотацию
/*#__PURE__*/
, которая обозначает отсутствие побочных эффектов в функции, для более эффективного тришейкинга (упомянал об этом в своём докладе).В самом JavaScript нет языкового средства для выражения чистоты функции — то есть отсутствия в ней эффектов, хотя было бы классно использовать это знание, например, для исполнения кода во время сборки (как, например, c babel-plugin-macros).
Apple Podcasts
Podlodka #404 – Системы эффектов в языках программирования
Выпуск подкаста · Podlodka Podcast · 23.12.2024 · 2 ч. 3 мин.
Пранк, который вышел из под контроля
Недавно решал проблему с тем, что после загрузки приложения происходит заметный скачок элементов страницы, связанный с загрузкой шрифтов.
В процессе исследования проблемы выяснилось, что @vitejs/plugin-legacy инлайнит CSS в JS-бандл с легаси сборкой, что приводит к тому, что шрифты гарантированно будут загружены после JS и скачок неизбежен.
Отказываться от plugin-legacy или возиться со сборкой было лень, поэтому я начал раздумывать над каким-то надёжным решением кроме инлайна шрифтов в base64 (чтобы они загружались синхронно).
По дороге из офиса домой я по традиции решил послушать выпуск веб-стандартов. Мне сразу показался подозрительным состав ведущих в этом выпуске, но я не придал этому особого значения. По счастливой случайности одной из обсуждаемых тем была загрузка шрифтов: обсуждали тот самый вариант с инлайном в base64, а так же некий новый Font Face API (почему-то я самостоятельно не догадался загуглить его), который ещё мало где поддерживается.
Придя домой, я наконец обратил внимание на дату публикации выпуска: он был датирован 1 апреля...
Это был выпуск веб-стандартов 10-лентней давности, а значит тот самый Font Face API уже давным давно "Baseline Widely Awailable" и ничто не мешает мне его использовать, чтобы управлять последовательностью загрузки ресурсов приложения:
Не сказал бы, что это это прям правильное решение проблемы, но в моём кейсе самым главным фактором было то, что оно даёт контроль над последовательностью загрузки ресурсов приложения и позволяет избежать гонок.
Таким образом выпуск веб-стандартов прошёл проверку временем и внезапно оказался полезен даже спустя 10 лет после выхода.
Недавно решал проблему с тем, что после загрузки приложения происходит заметный скачок элементов страницы, связанный с загрузкой шрифтов.
В процессе исследования проблемы выяснилось, что @vitejs/plugin-legacy инлайнит CSS в JS-бандл с легаси сборкой, что приводит к тому, что шрифты гарантированно будут загружены после JS и скачок неизбежен.
Отказываться от plugin-legacy или возиться со сборкой было лень, поэтому я начал раздумывать над каким-то надёжным решением кроме инлайна шрифтов в base64 (чтобы они загружались синхронно).
По дороге из офиса домой я по традиции решил послушать выпуск веб-стандартов. Мне сразу показался подозрительным состав ведущих в этом выпуске, но я не придал этому особого значения. По счастливой случайности одной из обсуждаемых тем была загрузка шрифтов: обсуждали тот самый вариант с инлайном в base64, а так же некий новый Font Face API (почему-то я самостоятельно не догадался загуглить его), который ещё мало где поддерживается.
Придя домой, я наконец обратил внимание на дату публикации выпуска: он был датирован 1 апреля...
Это был выпуск веб-стандартов 10-лентней давности, а значит тот самый Font Face API уже давным давно "Baseline Widely Awailable" и ничто не мешает мне его использовать, чтобы управлять последовательностью загрузки ресурсов приложения:
const font = new FontFace(
"my-font", "url(my-font.woff)",
{
style: "normal",
weight: "400",
stretch: "condensed",
}
);
Promise.all([
import("./app.js"),
font.load(),
]).then(([app]) => {
document.fonts.add(font);
app.init();
});
Не сказал бы, что это это прям правильное решение проблемы, но в моём кейсе самым главным фактором было то, что оно даёт контроль над последовательностью загрузки ресурсов приложения и позволяет избежать гонок.
Таким образом выпуск веб-стандартов прошёл проверку временем и внезапно оказался полезен даже спустя 10 лет после выхода.