{"version": "https://jsonfeed.org/version/1.1", "title": "Polymorphic Blueprint", "home_page_url": "https://t.me/contravariance", "feed_url": "https://tg.davvie.com/static/contravariance.json", "description": "Polymorphic Blueprint", "items": [{"id": "https://t.me/c/2068344133/391", "url": "https://t.me/c/2068344133/391", "title": "#metal #gpu #swift #highperf #ios  Folding animation machinery нового iPhone Duo реверс инжернирнут ", "content_html": "#metal #gpu #swift #highperf #ios<br /><br />Folding animation machinery нового iPhone Duo реверс инжернирнут на атомы.<br /><br />Хехе<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-09-17T16:48:10+00:00"}, {"id": "https://t.me/c/2068344133/390", "url": "https://t.me/c/2068344133/390", "title": "#applesilicon #xnu #hardware  iPhone Duo не замена iPad - у них совершенно разный energy profile.   ", "content_html": "#applesilicon #xnu #hardware<br /><br />iPhone Duo не замена iPad - у них совершенно разный energy profile. <br /><br />• У A чипов пиковый sustained TDP 6W / short bursts up to ~12W, у M чипов sustained 20W / short bursts up to ~30W; <br />• memory bandwidth 60GB/s (64 bit bus) vs 120GB/s (128 bit bus); <br /><br />Совершенно разный выходной комьют или это как сравнивать самолет с ракетой. Оба летают быстро, но есть нюанс или два. Не делайте категориальную ошибку.<br /><br /><blockquote>Примечательно, в A20 Pro происходит незаметный и важный эволюционный сдвиг: техпроцесс 2nm и переход на 96 bit bus, а с этим mem bandwidth теперь ~115GB/s (это выше, чем в M1, M2, и M3 ... и где то рядом с M4 (120GB/s) и M5 (153GB/s)). Sustained TDP тоже вырос на ~40%. Для <del>телефона</del> pocket-компьютера это микроархитектурное чудо уровня десктопа.<br /></blockquote><br /><br />Один лишь прыжок с 60GB/s сразу на 115GB/s (даже с 12GB unified memory) это разница между приемлемо работающей локальной модели и слайд шоу на 5-8tok/s / 6-10fps. <br /><br /><blockquote>XNU Edge/Clutch scheduler (вся работа вашего SC / GCD кода (*) c user space в kernel space проходит через него, ну та что не элайдится (thread switch or executor transfer hop elision) или не мерджается, через region based analysis например) работает <em>немного</em> (мягко говоря) по разному на обоих чипах. У них разная кластеризация (Edge специально разработан для AMP и тесно взаимодействует с CLPC) ядер и разные power preservation профиль распределения комьюта в энергосберегающем режиме (* там еще небольшая тележка thread groups, latency гарантий per bucket, warp механизм - в общем это целый scheduling machinery); <br /></blockquote><br /><br />В догонку - совершенно разный UX, форм фактор, да <del>даже</del> тем более target audience наконец. Про разницу в цене тоже часть людей забыла.<br /><br />Я вижу не замену чего то - чем то, а расширение рынка и возможностей, как <em>глубоко инженерны</em>х так и продуктовых. <br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-09-10T17:50:00+00:00"}, {"id": "https://t.me/c/2068344133/389", "url": "https://t.me/c/2068344133/389", "title": "#metal #gpu #swift #highperf #ios  It&#x27;s getting out of hand ... держим в уме, что это A16 Bioni", "content_html": "#metal #gpu #swift #highperf #ios<br /><br />It&#x27;s getting out of hand ... держим в уме, что это A16 Bionic 4х годичной давности.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-09-08T15:55:59+00:00"}, {"id": "https://t.me/c/2068344133/388", "url": "https://t.me/c/2068344133/388", "title": "#metal #gpu #swift #highperf #ios  Когда cable management важен везде vol II.   In English, we often", "content_html": "#metal #gpu #swift #highperf #ios<br /><br />Когда <a href=\"https://t.me/contravariance/382\">cable management</a> важен везде vol II. <br /><br /><blockquote>In English, we often say ambiguous things. We need a programming language that is precise; <a href=\"https://youtu.be/U46fJ2bJ-co?si=T7CEwkJrlFgQ4wqL&amp;t=5331\">that is engineering, and that is math</a>.<br /></blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-09-01T15:25:01+00:00"}, {"id": "https://t.me/c/2068344133/387", "url": "https://t.me/c/2068344133/387", "title": "#metal #swift #ios #highperf  Когда, то что вы смотрите, эффекты и анимации отрендерено на софте в .", "content_html": "#metal #swift #ios #highperf<br /><br />Когда, то что вы смотрите, эффекты и анимации отрендерено на софте в ... видосе или Darkroom Histogram вышел из чата<br /><br />p.s. это все одна платформа, начиная с поста про cable management<br /><br />p.p.s. скринкаст с iPhone 14 Pro hichless* 60-120 fps. В конце performance HUD показывает 2 fps - это 5 таймлайнов на <strong>паузе</strong> c 50+ эффектами<br /><br /><blockquote>2 fps здесь намеренный idle cadence кастомного frame scheduler: когда визуальное состояние не меняется, renderer не производит кадры с display rate частотой, а снижает частоту render loop и немедленно поднимает ee обратно при invalidation, interaction или playback. Для pro motion приложение задает допустимый диапазон, а фактическую частоту обновления дисплея выбирает система*<br /></blockquote><br /><br />Самое примечательное, что из 30 сек скринкаста, я 80% текста сконцентрировал на том &quot;почему 2 fps на экране с таймлайнами&quot; лол <br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-08-30T20:01:44+00:00"}, {"id": "https://t.me/c/2068344133/386", "url": "https://t.me/c/2068344133/386", "title": "Утром 26 августа на границе Китай-Непал пропал Саша Зимин, которого большинство из вас очень хорошо ", "content_html": "Утром 26 августа на границе Китай-Непал пропал Саша Зимин, которого большинство из вас очень хорошо знают. Ребята ищут хоть какую-то информацию от людей из групп, кого удалось спасти после сели – если вдруг у вас или ваших знакомых есть какие-то зацепки, свяжитесь с ними, пожалуйста.<br /><a href=\"https://www.instagram.com/reel/Dcj7BF9trF5/?igsi=a3FieWI4a2tmaHgz\">https://www.instagram.com/reel/Dcj7BF9trF5/?igsi=a3FieWI4a2tmaHgz</a>", "date_published": "2026-08-28T14:36:09+00:00"}, {"id": "https://t.me/c/2068344133/385", "url": "https://t.me/c/2068344133/385", "title": "Канал всегда был и остается в рамках инженерной эзотерики, но тут просьба распространить и по возмож", "content_html": "Канал всегда был и остается в рамках инженерной эзотерики, но тут просьба распространить и по возможности посодействовать 🙏 <br /><br />Берегите себя и близких", "date_published": "2026-08-28T14:36:09+00:00"}, {"id": "https://t.me/c/2068344133/384", "url": "https://t.me/c/2068344133/384", "title": "#metal #gpu #highperf #computelanguage #compositing   Each effect runs on a compute language that yo", "content_html": "#metal #gpu #highperf #computelanguage #compositing <br /><br />Each effect runs on a compute language that you&#x27;ve seen above, lol<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-08-20T18:26:53+00:00"}, {"id": "https://t.me/c/2068344133/383", "url": "https://t.me/c/2068344133/383", "title": "", "content_html": "", "date_published": "2026-08-12T13:24:03+00:00"}, {"id": "https://t.me/c/2068344133/382", "url": "https://t.me/c/2068344133/382", "title": "#metal #gpu #highperf #computelanguage   Когда cable management важен везде, даже в карманном comput", "content_html": "#metal #gpu #highperf #computelanguage <br /><br />Когда cable management важен везде, даже в карманном compute language. <br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-08-08T17:30:52+00:00"}, {"id": "https://t.me/c/2068344133/381", "url": "https://t.me/c/2068344133/381", "title": "", "content_html": "", "date_published": "2026-07-15T14:37:48+00:00"}, {"id": "https://t.me/c/2068344133/380", "url": "https://t.me/c/2068344133/380", "title": "#metal #physics #gpu #highperf #ui  Metal Graph-Node Editor.  Мне нужно было как то репрезентить, ре", "content_html": "#metal #physics #gpu #highperf #ui<br /><br /><strong>Metal Graph-Node Editor.</strong><br /><br />Мне нужно было как то репрезентить, редактировать, добавлять и удалять элементы сцены. Я не придумал ничего луче, чем написать прямо на GPU весь high-perf UI для нод-редактора, аля blueprints (который уже deprecated) в Unreal Engine. Well... микро версия, пока. Почему не кит или суи? Да просто бороться с тем, с чем можно не иметь дела крутое состояние. Написав UI сразу на Metal я открыл hichless опыт и возможность в 120 FPS рендерить тысячи нодов и десятки тысяч ребер графа, анимированных и с не менее fluid UX. <br /><br />Это все не без ряда ухищрений достигается, чуть-чуть комплекснее, чем закоммитить транзакцию на рендер сервер на следующем пасе.<br /><br />А да, чуть не забыл - адаптивная генерация геометрии для кривых Безье, одно из сотен условий для UI на GPU :D<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-07-01T19:04:45+00:00"}, {"id": "https://t.me/c/2068344133/379", "url": "https://t.me/c/2068344133/379", "title": "#metal #physics #gpu #highperf  Metal Physics Engine.  Мне было мало микро-yolo-poc простого басика ", "content_html": "#metal #physics #gpu #highperf<br /><br /><strong>Metal Physics Engine.</strong><br /><br />Мне было мало микро-yolo-poc <em>простого</em> басика и rubber-joint physics для утенка. По этому я взял некоторые богатство GPU Gems от Nvidia и написал полноценный движок для joint физики и physically based water simulation. <br /><br />Заодно realtime soft shadows with ambient occlusion, рефракции и еще ряд фич кастомного рендера и физ движка. <br /><br />Один GPU инженер не знакомый с тонкостями чипов Apple, был весьма впечатлен потенциалом железа. Сами подумайте: не самый новы чип A18 Pro в своей совокупности комьюта превосходит PS4, у вас в кармане (PS4: 1,84 TFLOPS vs iPhone 16 Pro (A18 Pro) 2,15–2,3 TFLOPS). Мы не говорим про М или более новые версии.<br /><br /><blockquote>Если все же будет интересно, тут некоторые фичи из симуляции:<br /><br /> • Realtime soft shadows<br /> • Ambient occlusion<br /> • Shadow-water-wave refraction <br /><br /> • New perspective 2d to 3d floating optical projection of duck <br /> • Self-shading on 3d floating projection physics movement <br /><br /> • Procedural pool<br /> • Custom tile pattern generator with persisting hash-seeds <br /><br /> • Water wave physics <br /> • Custom Water Postprocess Pipeline<br /> • Laplacian damped wave equation<br /> • Pool borders bounciness / interaction<br /> • Duck’s physics body interaction <br /> • Floating buoyancy physics <br /> • New wave heat map generation debug<br /> • Procedural pool bezel-border: a custom rounded rect SDF<br /> • Duck buoyancy movement  with injected elongated impulses ahead/behind motion<br /><br /> • New water refraction system<br /><br /> • Spring-joint system redux<br /> • Adjustable center of mass, rotation, size<br /> • New joint physics state heat map debug overlay <br /> • New spring physics state heat map debug overlay <br /><br /><br /> • Specular perspective transform light for the duck <br /> • Shadowmaped highmap to more accurately shade / project specular light</blockquote><br /><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-07-01T19:01:59+00:00"}, {"id": "https://t.me/c/2068344133/378", "url": "https://t.me/c/2068344133/378", "title": "#metal #physics #engine #simulation #ui   Footnote: Metal Spring Joint Physics Engine. Rubber duck p", "content_html": "#metal #physics #engine #simulation #ui <br /><br /><strong>Footnote: Metal Spring Joint Physics Engine. Rubber duck physics</strong>.<br /><br />Движок работает на кастомном multipass рендере, через compute kernel. <br /><br /><blockquote>Как нибудь покажу полную реплику порталирования, но не средствами CoreAnimation ака _UIPortalView / CAPortalView, а ... из игры Portal (Valve) в 2D, на Metal 🎸<br /></blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-28T07:59:22+00:00"}, {"id": "https://t.me/c/2068344133/377", "url": "https://t.me/c/2068344133/377", "title": "#metal #ui #highperf #pool   Hey, Pool App! I like your duck   p.s. приложение хорошо нашумело, там ", "content_html": "#metal #ui #highperf #pool <br /><br />Hey, <a href=\"https://apps.apple.com/us/app/pool-the-screenshot-app/id6752956163\">Pool App</a>! I like your duck <br /><br />p.s. приложение хорошо нашумело, там есть наши ребята @lovedeathstartups<br /><br />Я для утенка подогнал новый басик, ну и утенка апгрейднул :D<br /><br />Все процедурно на Metal, утенок - единственный импорируемый асет, растер управляемый кастомным spring joint animation engine: кастомная итерполяция текселей на джоинты. <br /><br />Все круто, но самое утомительное это подобрать во всей системе параметры... то утенок был надувным, то желейным...<br /><br /><blockquote><strong>Это не реклама, мне не платили и ребят я не знаю</strong>. Мне просто утка понравилась<strong><br /></strong></blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-27T22:18:52+00:00"}, {"id": "https://t.me/c/2068344133/376", "url": "https://t.me/c/2068344133/376", "title": "#metal #ui #highperf #gpu  Vol I. Footnote II: Geometry Subdivision Rolling Window, GPU Buffer Reuse", "content_html": "#metal #ui #highperf #gpu<br /><br /><strong>Vol I. Footnote II: Geometry Subdivision Rolling Window, GPU Buffer Reuse</strong>, <strong>15</strong> <strong>Parallel Video Streams</strong>, <strong>Low-Freq-High-Perf</strong>.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-27T06:44:20+00:00"}, {"id": "https://t.me/c/2068344133/375", "url": "https://t.me/c/2068344133/375", "title": "#metal #ui #highperf #gpu  Vol I. Footnote: Reverse Cylindric Roll Transform. Shadow Casting + Soft ", "content_html": "#metal #ui #highperf #gpu<br /><br /><strong>Vol I. Footnote</strong>:<strong> Reverse Cylindric Roll Transform. Shadow Casting + Soft Shading.<br /></strong><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-26T22:05:09+00:00"}, {"id": "https://t.me/c/2068344133/374", "url": "https://t.me/c/2068344133/374", "title": "#metal #ui #highperf #gpu  Metal High Performance Video Feed. 15 Streams, Shadow Casting, Cylindric ", "content_html": "#metal #ui #highperf #gpu<br /><br /><strong>Metal High Performance Video Feed. 15 Streams, Shadow Casting, Cylindric Roll Transformations. Vol I.<br /></strong><br />@lazy_var сделал крутые посты по цилиндрическому ролу для произвольных scrollable UI компонент, одним из самых перформант способов доступных легальным способом на Apple OSs. <br /><br />Я покажу, как выглядит построенный from ground up весь пайплайн high-performance feed с тем же цилинтрическим ролом, но на GPU через трио vertex, tesselation и fragment шейдерах, на кастомном не менее high perf рендере. И не просто статический контент... кто то говорит, что больше 2-3 потоков видео не запустить, декодеры yada-yada... это и правда и нет.<br /><br />Как говориться, hold my beer... 15 потоков видео на high-perf фид ленте утилизируя весь компьют и практически не нагружая main thread. Практически zero UIKit и ровно zero SwiftUI.<br /><br />У коллекции на голом Metal есть реюз (как у UICollectionView), rolling tesselation window - кто говорил что DSA не нужны в мобилке - это окно тесселяции, там где происходит цилиндрический бендинг я делаю сабдивижен геометрии, а там где cells физически всегда плоские - тесселяция всегда отключена - простой triangle strip (можно понимать, как два треугольника и общим index buffer - минус пара вертексов на каждый vertex draw call) - экономия за счет vertex winding order. <br /><br />Что по видео фиду? Можно lossless компрессить поток на комьют кернеле, ресемлировать на фрагментом стейдже, в общем 15 видео потоков на GPU занимают в пике... чуть больше 300Мб. В среднем - 150-180. А ну еще это в 120FPS Pro Motion работает. Минимальный таргет iOS 16+ - мне там некоторые части метала нужны были. Видео feeds не нужно делать полностью из ... непрерывно воспроизводимого видео, но это не про продукт - а про deep tech. <br /><br /><blockquote>stalls на записи это дебагер и видеорекордер</blockquote><br /><br />Dynamic Island теперь ... кастит коническую тень на видео фид. Все честно считается, а debug button кастит тень и через CoreAnimation синкнут с elastic easing functions связывая все в единое целое.<br /><br />Там миллион параметров торчит наружу, еще больше в API; <br /><br /><blockquote>Один крутой инженер из Nvidia говорит, что фид ленты 92% бигтехов и больших команд никогда не смогут сделать перформант. Не потому, что инженеры не такие какие то - нет они умные и опытные, мне есть чему учиться у вас всех - просто они сковывают себя рамками и борятся с тем, с чем можно просто не иметь дела. Можно подумать, при чем тут Nvidia :]<br /></blockquote><br />...<br /><br />Может сделаю вторую часть, Vol I тут скорее номинально для того, чтобы показать, что тема и материал - весьма глубокий и обширный. Stay tuned. <br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-26T20:34:47+00:00"}, {"id": "https://t.me/c/2068344133/373", "url": "https://t.me/c/2068344133/373", "title": "#metal #ui #cg #computergraphics #rendering #gpu  Multipass Rendering. Ping-Pong Render. Vol II. Dou", "content_html": "#metal #ui #cg #computergraphics #rendering #gpu<br /><br /><strong>Multipass Rendering. Ping-Pong Render. Vol II. Double Feedback Loop. Part II.<br /></strong><br />В <a href=\"https://t.me/contravariance/368\">Vol I</a> вся сложность жила в математике одного шейдера. В Frost Renderer примечательный момент - там, где обычно используют preloaded normal/noise текстуры (typical bump-mapping подход), можно вместо этого генерировать Worley (cellular) noise прямо во фрагментном шейдере, без единого байта текстуры на диске:<br /><br /><pre><br />    <code class='language-metal'><br />        <br />static float worley(float2 uv, float scale) {<br />    float2 p = uv * scale;<br />    float2 cell = floor(p);<br />    float2 f = fract(p);<br />    float minDist = 1.0;<br />    for (int y = -1; y &lt;= 1; y++)<br />        for (int x = -1; x &lt;= 1; x++) {<br />            float2 point = hash(cell + float2(x,y));<br />            minDist = min(minDist, length(float2(x,y) + point - f));<br />        }<br />    return minDist;<br />}<br />{}<br />    </code><br /></pre><br /><br />Это не микро оптимизация - это устранение целого класса зависимостей: no asset pipeline, no texture loading, no VRAM footprint под noise maps, no licensing вопросов на текстуры. Трейдофф - несколько дополнительных ALU операций на пиксель (3×3 cell lookup), что на практике дешевле, чем bandwidth на текстурный fetch с произвольным noise-семплом, особенно если noise нужен на нескольких разных масштабах одновременно (как в случае с fiber-стрики и deep-freeze peaks читают один и тот же procedural noise на разных scale-параметрах, без необходимости держать несколько preloaded текстур разных размеров).<br /><br /><blockquote>Как то была дискуссия, как с меньшими трейдофами задизайнить погодные эффекты в Weather App. Был аргумент, что эффективнее все запечь в alpha-blended .hevc x264-265 (а зависимости от наличия декодеров на конкретном SoC). Аргумент очевидно валидный, если не учесть одно но - если нам надо как то взаимодействовать с этими эффектами. Запечь уже не получиться все (либо вовсе ничего) - по этому полностью процедурный подход все же имеет свою ценность в ряде случаев.<br /></blockquote><br /><br /><blockquote>Когда есть функция шума, нужно еще одно свойство, чтобы эффект выглядел правдоподобно. Слово <em>анизотропный</em> вы могли встречать в контексте anisotropic filtering -  это другой, несвязанный концепт (про сэмплинг текстур под углом), просто термин совпадает. Здесь речь про анизотропный шум: изотропный (isotropic) шум выглядит одинаково во всех направлениях - нет выделенной оси, визуально читается как равномерный. Анизотропный - разный вдоль разных осей: структура вдоль одного направления отличается от перпендикулярного. Так обычно растут кристаллы изморози - направленно, а не равномерно. Конкретный метод может быть сколь угодно простым/сложным, важен принцип и выделенный фрагментный композитинг.</blockquote><br /><br /><strong>Видео как backgroundTexture: zero-copy через CVMetalTextureCache<br /></strong><br />В <a href=\"https://t.me/contravariance/368\">Vol I</a><code> </code>background был статичной текстурой. Frost Renderer поддерживает live video feed как background - это требует моста между AVFoundation pixel buffers и Metal текстурами без копирования байтов на CPU:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />CVMetalTextureCacheCreateTextureFromImage(<br />    nil, textureCache, pixelBuffer, nil,<br />    .bgra8Unorm, width, height, 0, &amp;cvTexture<br />)<br />let texture = CVMetalTextureGetTexture(cvTexture!)! // NIT: simplification<br />{}<br />    </code><br /></pre><br /><br /><code>CVPixelBuffer</code> (decoder output) и <code>MTLTexture</code> (GPU-sampleable resource) указывают на общую <code>IOSurface</code>-backed память - <code>CVMetalTextureCacheCreateTextureFromImage</code> не копирует пиксели, а создаёт Metal совместимый view поверх уже существующей видеопамяти. Ключевая deталь, без которой это не работает - <code>kCVPixelBufferMetalCompatibilityKey</code>: <code>true</code> в <code>pixelBufferAttributes</code> при создании <code>AVPlayerItemVideoOutput</code>: без этого флага <code>CVMetalTextureCacheCreateTextureFromImage</code> может вернуть <code>nil</code> без явной ошибки, и дебажить такое - отдельное удовольствие.<br /><br /><blockquote>Самое примечательное, что этот рендер не только весьма легковестный, но и отлично интегрируется в любой интерактивный или/и анимированный UI flow. Так как все параметрическое, то возможны вариации от cartoonish до фотореализма.</blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-22T16:12:15+00:00"}, {"id": "https://t.me/c/2068344133/372", "url": "https://t.me/c/2068344133/372", "title": "#metal #ui #cg #computergraphics #rendering #gpu  Multipass Rendering. Ping-Pong Render. Vol II. Dou", "content_html": "#metal #ui #cg #computergraphics #rendering #gpu<br /><br /><strong>Multipass Rendering. Ping-Pong Render. Vol II. Double Feedback Loop. Part I.<br /></strong><br />Тот же метод, но два независимых feedback-буфера (A, B) + один non-feedback composite pass (C). Эффект выглядит сложнее, но парадоксально на фрагментный пайплайн накладывается существенно меньший комьют даже с двойным feedback-буфером, потому что update-пассы A и B тривиальны (decay + write), а вся сложность ушла в noise generation внутри compose pass (С - composite pass), а не в feedback loops (A и B).<br /><br />В первой части мы разобрали ping-pong как паттерн для одной эволюционирующей текстуры - rubber cloth slider, где state - это позиция анкера, затухающая к центру. Frost Renderer: эффект изморози на стекле, который скретчится касанием и нарастает обратно слоями, non-uniformly. Тот же фундамент, но три буфера вместо одного - и именно это даёт качественно новый результат.<br /><br /><br /><strong>Зачем три буфера, если идея та же?<br /></strong><br />Один ping-pong буфer кодирует одну скорость эволюции состояния. Rubber cloth релаксировал к центру с одной константой затухания - этого достаточно для одной физической величины.<br />Frost-эффект визуально состоит из двух фаз, которые обязаны жить с разными temporal constants:<br />• <code>Buffer A</code> - быстрая фаза: скретч-trail, который тает за доли секунды (decay ~0.97 per frame)<br />• <code>Buffer B</code> - медленная фаза: глубокая заморозка, которая держится секундами (decay ~0.995 per frame)<br /><br />Один скаляр не может одновременно затухать с двумя разными константами. Если попытаться воспроизвести обе фазы в одной текстуре (например, в разных каналах RGBA одного буфера), update-шейдер все равно должен применить разные decay-формулы к разным каналам в одном write - технически возможно, но это смешивает две независимые системы состояния в одну текстуру, что усложняет дальнейшую композицию (нельзя, например, передать одну фазу в другой шейдер без нарезки каналов) и убирает архитектурную гибкость иметь раздельные pixel formats, resolution, или update rate под каждую фазу при необходимости.<br /><br />Архитектура: 3х read/write loops и один финальныый composite pass<br /><br />Frame N:<br />• <code>Pass 0:</code> Buffer A update (читает <code>A[N-1</code>], пишет <code>A[N]</code>) → fast scratch decay<br />• <code>Pass 1:</code> Buffer B update (читает <code>B[N-1]</code>, пишет <code>B[N]</code>) → slow freeze decay<br />• <code>Pass 2:</code>Final composite (читает <code>A[N], B[N]</code>, background, normal maps) → drawable<br /><br />Два независимых ping-pong пара (A читает/пишет себя, B читает/пишет себя - они не зависят друг от друга на стадии update), и только в финальном compose-пассе их результаты сходятся вместе. Это важный архитектурный нюасн: <code>Buffer A</code> и <code>Buffer B</code> не знают о существовании друг друга до самого последнего пасса - каждый эволюционирует как полностью независимая DP-цепочка.<br /><br />Что объединяет рендер из прошлой части с frost render? Тот же DP-фреймворк, но теперь это не одна рекуррентная переменная, а система из двух независимых рекуррентных переменных, которые объединяются только на стадии &quot;вывода&quot; (compose), не на стадии &quot;обновления&quot; (update). Это прямая аналогия с тем, как в DP можно держать несколько независимых таблиц состояний (например, <code>dp1[i]</code>, <code>dp2[i]</code> с разными переходами) и комбинировать их только в финальной формуле.<br /><br /><blockquote>~0.5ms render frame, A18, release mode, aarch64 Swift 6.3.1, iOS 26.5)</blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-22T16:12:10+00:00"}, {"id": "https://t.me/c/2068344133/368", "url": "https://t.me/c/2068344133/368", "title": "#metal #ui #cg #rendering #gpu  Multipass Rendering. Ping-Pong Render. Vol I.   Это серия из минимум", "content_html": "#metal #ui #cg #rendering #gpu<br /><br /><strong>Multipass Rendering. Ping-Pong Render. Vol I. </strong><br /><br />Это серия из минимум двух частей про advanced computer graphics &amp; GPU programming. Я вам покажу в этом и следующем посте две принципиально разные симуляции, но их обьеденяет один концептуально идентичный рендер; рендер построен вокруг идеи некоторой feedback текстуры - буффера, которые можно чейнить для композитинга более сложных фрагментных и вертексных стейджей GPU пайплайна. <br /><br /><blockquote>Идея feedback texture заключается в рендер таргете, который становится инпутом для следующего фрейма. Концептуально это некоторая форма динамического программирования на GPU. Ну и кто сказал, что алгосы (DSA) не пригодятся :D<br />В компьютерной графике это feedback loop - паттерн рендеринга, где output каждого фрейма зависит от state предыдущего фрейма; вычисленный результат идет обратно на вход следующей итерации, создавая непрерывную эволюцию данных во времени.</blockquote><br /><br />Две текстуры A и B, свапаются каждый фрейм. Фрейм N рендерин в A, в то время пока читает из B - инпут последнего фрейма. Фрем N+1 рендерит в B пока читает А. GPU никогда не читает и не пишет в одну текстуру в одном пасе - это нелегальная операция в Metal - explicit validation error (для compute kernels через read_write текстуры - другая история, там UB реальна). От сюда и название - ping-pong - или два буфера симулируют одну персистентную текстуру, которая мутирует в каждым кадром.<br /><br /><blockquote>Ping-pong как форма multipass - технически это частный случай multipass rendering: несколько проходов, каждый со своим render target. Но не каждый multipass - ping-pong. Ping-pong это multipass с temporal feedback: специфика именно в том, что output одного фрейма становится input следующего, а не просто &quot;несколько проходов в одном фрейме&quot;.</blockquote><br /><br />Это знание открывает принципиально новый мир лоу-лвл GPU дизайна. Round-trip между CPU и GPU даже на гетерогенной архитектуре это недешевое удовольствие. GPU мейнтейнит свою область памяти, где весь стейт относительно paint trails, decaying scratches, relaxing cloth anchors etc живет в двух преаллоцированных фрейм-буферах, без CPU-related фидбека стейта на каждый кадр (storageMode: .private). <br />CPU передаёт только малый uniform buffer (touch up/down, drag, frame, velocity, parameters) - а весь объемный state (текстуры) остаётся резидентным в GPU между кадрами - CPU вообще не видит и не трогает байты текстур.<br /><br />На самом GPU мы можешь отдельно компьютить эволюцию состояния симуляции (текстура A), а в отдельной шейдере рендерить результат стейта (текстура B). Архитектурно перенося хранение, обновление состояния аля view model, но во фреймбуфере и не покидая GPU, и отображая результат аля presentation/view слой, но уже в соседнем фреймбуфере и опять же не покидая GPU.<br /><br />В такой модели мы не только держим данные, о состоянии и рендеринге максимально близко - максимально нивелируя многие проблемы data locality между update/render стадиями - но мы так же переиспользуем богатую GPU инфраструктуру в виде семплеров, блендинг фунций и RGBA текселей.<br /><br />Трейдоффом выступает ограничениями точности текстурного формата - GPU и Metal не всесильны тут. <br /><br />Ping-ponging так же подвержена ошибкам в порядке swap’инга буферов, которая выглядит как race condition, но детерминирована - в рамках одного MTLCommandBuffer с правильным swap race condition невозможна (не memory hazard) - Metal гарантирует порядок энкодинга команд в буфере.<br />Лейаут unimorf&#x27;ов нужно синхронизировать между GPU и CPU, не самые очевидные способы unit тестирования. Хотя, вопреки распространненному заблуждению, шейдеры юнит тестятся и весьма успешно (offline Metal compute dispatch, или просто golden-image diffing).<br /><br /><blockquote>Ping-pong - это swap указателей, а не копирование данных. Реализация через read/write/swap() - swap-метод просто обменивает ссылки между двумя буфера без копирования. Самой свап-операции тоже нет физического memmove, только переключение указателей буферов.</blockquote><br /><br />• <a href=\"https://ostefani.dev/tech-notes/ping-pong-technique\">Stateful Rendering with the Ping-Pong Technique</a><br />• <a href=\"https://developer.apple.com/documentation/metal/mtlstoragemode/private\">MTLStorageMode.private</a><br />• <a href=\"https://developer.apple.com/documentation/metal/setting-resource-storage-modes\">Setting resource storage modes</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-20T15:38:16+00:00"}, {"id": "https://t.me/c/2068344133/367", "url": "https://t.me/c/2068344133/367", "title": "#wwdc26 #swiftui #typechecker #swift  @ContentBuilder с бекпортом до iOS 13.0+ | iPadOS 13.0+ | Mac ", "content_html": "#wwdc26 #swiftui #typechecker #swift<br /><br /><a href=\"https://developer.apple.com/documentation/swiftui/contentbuilder\">@ContentBuilder с бекпортом </a>до iOS 13.0+ | iPadOS 13.0+ | Mac Catalyst 13.0+ | macOS 10.15+ | tvOS 13.0+ | visionOS 1.0+ | watchOS 6.0+<br /><br />ContentBuilder = ViewBuilder алиас прозрачен для constraint solver&#x27;а, судя по всему это не про subtyping trick. Магия в conditional conformance на результирующих типах (TupleContent и подобных), плюс сдвиг от overload resolution на constraint стороне buildBlock к conformance lookup на стороне результирующего типа. Именно поэтому проблема комбинаторного взрыва операторов сюда не переносится.<br /><br />Вместе с @ContentBuilder вводятся ряд других, конкретных билдеров (они в основом без бекпорта):<br />• CompositorContentBuilder<br />• KeyframeTrackContentBuilder<br />• ToolbarContentBuilder<br />• TabContentBuilder<br />• ImmersiveSpaceContentBuilder<br />...<br /><br /><blockquote><a href=\"https://t.me/contravariance/335\">Тред Славы Пестова про constraint solver</a> это пока то, что в своей самой зачаточной форме попадет в Swift 6.4, в <a href=\"https://github.com/swiftlang/swift/pull/84993\">отдельных патчах</a>. В Swift 6.3 вошли оптимизации disjunction selection и constraint solver arena usage. Более продвинутые и существенно менее тривиальные изменения constraint solver&#x27;a такие как clause learning, <a href=\"https://vaibhavsagar.com/blog/2025/10/22/satisfying-solutions/\">Boolean formula satisfiability</a> и non-chronological backtracking.</blockquote><br /><br />В остальном, все что было на даб-дабе про type ambiguity resolution это в большей степени про архитектуру SwiftUI, его дизайн токены и отдельные изменения.<br /><br />• <a href=\"https://forums.swift.org/t/how-does-compiler-compile-swiftui-code/78483/4\">How does compiler compile SwiftUI code?<br /></a>• <a href=\"https://forums.swift.org/t/what-is-wrong-with-type-inference/78690/2\">What is wrong with type inference?<br /></a>• <a href=\"https://forums.swift.org/t/replacing-the-type-checker/79518/80\">Replacing the Type Checker</a> <a href=\"https://forums.swift.org/t/how-does-compiler-compile-swiftui-code/78483/4\"><br /></a>• <a href=\"https://github.com/swiftlang/swift/blob/main/docs/TypeChecker.md\">swift/docs/TypeChecker.md<br /></a>• <a href=\"https://www.youtube.com/watch?v=IbjoA5xVUq0\">A Type System From Scratch – Robert Widmann</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-09T17:08:00+00:00"}, {"id": "https://t.me/c/2068344133/366", "url": "https://t.me/c/2068344133/366", "title": "#wwdc26 #uikit #apidiff   Тем временем новые UIKit API (ObjC API Diff: iOS 26.2 → iOS 27 (beta))  @c", "content_html": "#wwdc26 #uikit #apidiff <br /><br />Тем временем новые UIKit <a href=\"https://gist.github.com/kylehowells/32c7f7475698b5f74eeb183f8db9d186\">API (ObjC API Diff: iOS 26.2 → iOS 27 (beta))</a><br /><br />@contravariance<br /><img src=\"https://tg.davvie.com/static/-1002068344133--366-0.jpg\" alt=\"media\"/>", "date_published": "2026-06-09T04:31:27+00:00", "attachments": [{"url": "https://tg.davvie.com/static/-1002068344133--366-0.jpg", "mime_type": "image/jpeg"}]}, {"id": "https://t.me/c/2068344133/365", "url": "https://t.me/c/2068344133/365", "title": "#swift #concurrency #compiler   Swift 6.4 cancellation shields: от семантики до самых недр компилято", "content_html": "#swift #concurrency #compiler <br /><br /><strong>Swift 6.4 cancellation shields</strong>: от семантики до самых недр компилятора, с полным трейсом всех изменений с фронтенда до билтинов. <br /><br />• Что такое cancellation shields?<br />• Некоторые детали того, как работал флаг кооперативной отмены задач и как он теперь работает?<br />• Какие задачи решает cancellation shields?<br />• Возможно сподвигнет чуток глубже в cooperative cancellation model погрузиться (хоть это и малая, но значимая часть всей модели) - Swift Concurrency уже без малого +5 лет - имхо пора давно осваивать.<br />• Материал не для новичков, но может мотивировать размотать весь клубок связных концепций.<br /><br />• <a href=\"https://t.me/contravariance/362\">Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol I.<br /></a>• <a href=\"https://t.me/contravariance/363\">Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol II.<br /></a>• <a href=\"https://t.me/contravariance/364\">Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol III.</a><br /><br />В одной из следующих серий: Task Tree и подкапотные механизмы Swift Concurrency. Разберем, как на самом деле пропагируются контекст задач, изоляция и TaskLocal значения. Поговорим о том, почему в Swift 6.4 компилятор изменил низкоуровневую реализацию intrusive tree design и почему интрузивный дизайн - это один из самых эффективных способов построения рекурсивных моделей данных без лишних аллокаций с учетом cache locality.<br /><br />А пока - happy dub-dub! 🥳<br /><br />@contravariance", "date_published": "2026-06-08T13:20:28+00:00"}, {"id": "https://t.me/c/2068344133/364", "url": "https://t.me/c/2068344133/364", "title": "#swift #concurrency #compiler  Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol III.  ", "content_html": "#swift #concurrency #compiler<br /><br /><strong>Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol III.</strong><br /><br /><br />IRGen понижает (via lowering phase) эти Builtins не в LLVM intrinsic, а в runtime calls:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />case BuiltinValueKind::TaskCancellationShieldPush:<br />  out.add(emitBuiltinTaskCancellationShieldPush(IGF));<br />  return;<br /><br />case BuiltinValueKind::TaskCancellationShieldPop:<br />  return emitBuiltinTaskCancellationShieldPop(IGF);<br />{}<br />    </code><br /></pre><br /><br />А сами emitters вызывают runtime function pointers:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />llvm::Value *irgen::emitBuiltinTaskCancellationShieldPush(IRGenFunction &amp;IGF) {<br />  auto *call =<br />      IGF.Builder.CreateCall(IGF.IGM.getTaskCancellationShieldPushFunctionPointer(), {});<br />  call-&gt;setDoesNotThrow();<br />  call-&gt;setCallingConv(IGF.IGM.SwiftCC);<br />  return call;<br />}<br /><br />void irgen::emitBuiltinTaskCancellationShieldPop(IRGenFunction &amp;IGF) {<br />  auto *call =<br />      IGF.Builder.CreateCall(IGF.IGM.getTaskCancellationShieldPopFunctionPointer(), {});<br />  call-&gt;setDoesNotThrow();<br />  call-&gt;setCallingConv(IGF.IGM.SwiftCC);<br />}<br />{}<br />    </code><br /></pre><br /><br />Runtime symbols:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />swift_task_cancellationShieldPush<br />swift_task_cancellationShieldPop<br />swift_task_hasActiveCancellationShield<br />{}<br />    </code><br /></pre><br /><br />И уже в concurrency runtime это приземляется в AsyncTask::cancellationShieldPush() / AsyncTask::cancellationShieldPop(), где в ActiveTaskStatus ставится или снимается флаг:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />HasActiveTaskCancellationShield = 0x10000<br />{}<br />    </code><br /></pre><br /><br />Фактически shield state живет в task status flags, а isCancelled теперь умеет учитывать этот флаг:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />bool isCancelled(bool ignoreShield = false) const {<br />  return (Flags &amp; IsCancelled) &amp;&amp;<br />         (ignoreShield || !(Flags &amp; HasActiveTaskCancellationShield));<br />}{}<br />    </code><br /></pre><br /><br />• <a href=\"https://github.com/swiftlang/swift-evolution/blob/main/proposals/0504-task-cancellation-shields.md\">/swiftlang/swift-evolution/blob/main/proposals/0504-task-cancellation-shields.md</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/stdlib/public/Concurrency/TaskCancellation.swift#L126-L130\">/swiftlang/swift/blob/release/6.3/stdlib/public/Concurrency/TaskCancellation.swift#L126-L130</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L200-L258\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L200-L258</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L376-L386\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L376-L386</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L470-L480\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L470-L480</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L488-L517\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskCancellation.swift#L488-L517</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/include/swift/Basic/Features.def#L281\">/swiftlang/swift/blob/release/6.4.x/include/swift/Basic/Features.def#L281</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/include/swift/AST/Builtins.def#L1265-L1273\">/swiftlang/swift/blob/release/6.4.x/include/swift/AST/Builtins.def#L1265-L1273</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/lib/AST/Builtins.cpp#L2484-L2490\">/swiftlang/swift/blob/release/6.4.x/lib/AST/Builtins.cpp#L2484-L2490</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/lib/IRGen/GenBuiltin.cpp#L1602-L1606\">/swiftlang/swift/blob/release/6.4.x/lib/IRGen/GenBuiltin.cpp#L1602-L1606</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/lib/IRGen/GenConcurrency.cpp#L371-L383\">/swiftlang/swift/blob/release/6.4.x/lib/IRGen/GenConcurrency.cpp#L371-L383</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/include/swift/Runtime/RuntimeFunctions.def#L2745-L2768\">/swiftlang/swift/blob/release/6.4.x/include/swift/Runtime/RuntimeFunctions.def#L2745-L2768</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/include/swift/Runtime/Concurrency.h#L607-L625\">/swiftlang/swift/blob/release/6.4.x/include/swift/Runtime/Concurrency.h#L607-L625</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/include/swift/Runtime/Concurrency.h#L744-L759\">/swiftlang/swift/blob/release/6.4.x/include/swift/Runtime/Concurrency.h#L744-L759</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/Task.cpp#L1761-L1769\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/Task.cpp#L1761-L1769</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/Task.cpp#L1853-L1874\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/Task.cpp#L1853-L1874</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskPrivate.h#L489-L566\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskPrivate.h#L489-L566</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskPrivate.h#L1343-L1375\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskPrivate.h#L1343-L1375</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskStatus.cpp#L858-L866\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/Concurrency/TaskStatus.cpp#L858-L866</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/test/SILGen/builtins.swift#L1012-L1023\">/swiftlang/swift/blob/release/6.4.x/test/SILGen/builtins.swift#L1012-L1023</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-08T13:06:14+00:00"}, {"id": "https://t.me/c/2068344133/363", "url": "https://t.me/c/2068344133/363", "title": "#swift #concurrency #compiler  Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol II.  В", "content_html": "#swift #concurrency #compiler<br /><br /><strong>Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol II.</strong><br /><br />Важно помнить простую эвристику: если нужен actual cancellation state конкретного task handle, смотрим через taskHandle.isCancelled или UnsafeCurrentTask.isCancelled. Если нужен кооперативный флаг отмены текущего execution context, с учетом shielded lexical scope, смотрим через Task.isCancelled.<br /><br />• Получить handle на текущую задачу можно через withUnsafeCurrentTask { }.<br />• Получить статус наличия cancellation shield у текущей задачи в текущем лексическом scope можно через Task.hasActiveCancellationShield.<br />• Для unsafe handle есть аналогичный UnsafeCurrentTask.hasActiveCancellationShield.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />@available(SwiftStdlib 6.4, *)<br />extension Task where Success == Never, Failure == Never {<br />  @available(SwiftStdlib 6.4, *)<br />  @_alwaysEmitIntoClient<br />  public static var hasActiveCancellationShield: Bool {<br />    @_alwaysEmitIntoClient<br />    get {<br />      unsafe withUnsafeCurrentTask { task in<br />        unsafe task?.hasActiveCancellationShield ?? false<br />      }<br />    }<br />  }<br />}<br />{}<br />    </code><br /></pre><br />На компиляторном уровне это выглядит так: $BuiltinTaskCancellationShield - это feature gate, а сами примитивы лежат как Swift Builtins: Builtin.taskCancellationShieldPush() и Builtin.taskCancellationShieldPop().<br /><br />Они объявлены в compiler builtin table:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />BUILTIN_MISC_OPERATION(TaskCancellationShieldPush, &quot;taskCancellationShieldPush&quot;, &quot;&quot;, Special)<br />BUILTIN_MISC_OPERATION(TaskCancellationShieldPop, &quot;taskCancellationShieldPop&quot;, &quot;&quot;, Special)<br />{}<br />    </code><br /></pre><br /><br />Дальше lib/AST/Builtins.cpp задает им сигнатуры:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />static ValueDecl *getTaskCancellationShieldPush(ASTContext &amp;ctx, Identifier id) {<br />  return getBuiltinFunction(ctx, id, _thin, _parameters(), _int(1));<br />}<br /><br />static ValueDecl *getTaskCancellationShieldPop(ASTContext &amp;ctx, Identifier id) {<br />  return getBuiltinFunction(ctx, id, _thin, _parameters(), _void);<br />}<br />{}<br />    </code><br /></pre><br /><br />push возвращает Builtin.Int1 / Bool, потому что nested shield не устанавливает второй shield. Если shield уже активен, push вернет false, и этот scope не должен делать pop.<br /><br />В TaskCancellation.swift это видно прямо:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />let didInstallShield = Builtin.taskCancellationShieldPush()<br /><br />defer {<br />  if Bool(didInstallShield) {<br />    Builtin.taskCancellationShieldPop()<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-08T13:06:03+00:00"}, {"id": "https://t.me/c/2068344133/362", "url": "https://t.me/c/2068344133/362", "title": "#swift #concurrency #compiler  Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol I.  По", "content_html": "#swift #concurrency #compiler<br /><br /><strong>Swift 6.4: Concurrency. Demystifying Cancellation Shields. Vol I.</strong><br /><br /><blockquote>Пост расчитан на ваше понимание cooperative cancellation concurrency model, умение мануально связывать unstructed tasks и пропагировать cancellation state. <br /><br />Полный трейс всех 19 компиляторных референсов приведен в Vol III - вы можете этот rabbit hole с фронтенда до билтинов пройтись.</blockquote><br /><br />Concurrency примечательно и точечно реинженирят - помимо очевидных и видимых изменений, в 6.4 уже вошли многие менее очевидные. Например, task tree изменил свою модель с intrusive single linked list на intrusive doubly linked list, но об этом отдельно.<br /><br />Cancellation propagation в кооперативной модели конкурентности Swift Concurrency претерпел изменения. Если раньше инвариант cancellation был терминальным и монотонным, то есть если флаг был флипнут, то анфлипнуть его снова уже не было возможности, он мог быть установлен в состояние отмены (cancellation state == true) ровно один раз.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />@available(SwiftStdlib 5.1, *)<br />extension Task {<br />  @_transparent public var isCancelled: Bool {<br />    _taskIsCancelled(_task)<br />  }<br />}<br /><br />@available(SwiftStdlib 5.1, *)<br />extension Task where Success == Never, Failure == Never {<br />  public static var isCancelled: Bool {<br />     unsafe withUnsafeCurrentTask { task in<br />       unsafe task?.isCancelled ?? false<br />     }<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br />Мы можем это состояние проверить как через instance task handle, так и через тип Task, e.g. task.isCancelled vs Task.isCancelled. До введения cancellation shields, если говорить именно о текущей задаче, семантической разницы почти не было, были в основном лексические различия.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />/// After the value of this property becomes `true`, it remains `true` indefinitely.<br />/// There is no way to uncancel a task.<br />{}<br />    </code><br /></pre><br /><br />Теперь же инвариант isCancelled, через cancellation shield (SE-0504), будет слегка по-разному работать через instance vs type: source of truth vs lexical scope shielding.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />@_transparent<br />public var isCancelled: Bool {<br />  // This is @available(SwiftStdlib 6.4, *) but can&#x27;t use SwiftStdlib in transparent function<br />  if #available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999, *) {<br />    let ignoreTaskCancellationShield: UInt64 = 0x1<br />    return _taskIsCancelledWithFlags(_task, flags: ignoreTaskCancellationShield)<br />  } else {<br />    return _taskIsCancelled(_task)<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br /><pre><br />    <code class='language-swift'><br />        <br />public static var isCancelled: Bool {<br />  unsafe withUnsafeCurrentTask { task in<br />    if #available(SwiftStdlib 6.4, *) {<br />      unsafe task?._isCancelled(ignoreTaskCancellationShield: false) ?? false<br />    } else {<br />      unsafe task?.isCancelled ?? false<br />    }<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br />То есть shield-aware поведение появляется именно для Task.isCancelled и Task.checkCancellation(). Для taskHandle.isCancelled все остается по-прежнему: instance property не контекстуальна и игнорирует shield.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />/// ### Instance property isCancelled ignores Task Cancellation Shields<br />///<br />/// The instance property `task.isCancelled`<br />/// is not contextual and therefore does not respect cancellation shields.<br />/// If a task was cancelled and is executing with an active cancellation shield,<br />/// these properties will return the _actual_ cancellation status of the specific task.<br />{}<br />    </code><br /></pre><br /><br />Это сделано для возможности изолировать (e.g. шилдить) отдельные лексические скоупы от кооперативной отмены. Изоляция тут <em>плохое слово</em>, потому что isolation имеет совершенно иной семантический и компилятивный смысл. Cancellation shield не “отменяет отмену” (масло маслянное) и не делает task uncancelled. Он только временно запрещает коду внутри скоупа <em>наблюдать</em> cancellation state.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-06-08T13:05:56+00:00"}, {"id": "https://t.me/c/2068344133/361", "url": "https://t.me/c/2068344133/361", "title": "#swift #compiler #evolution  Quick Tip: Will be an error in Swift 7 language mode  cc: @maximkrouk  ", "content_html": "#swift #compiler #evolution<br /><br /><strong>Quick Tip: Will be an error in Swift 7 language mode</strong><br /><br /><blockquote>cc: @maximkrouk</blockquote><br /><br />Если вы встретите или уже встретили &quot;will be an error in Swift 7 language mode&quot; - не пугайтесь, скорее всего один этих флагов тригернулся:<br /><br />• <code>ExistentialAny</code> (SE-0335)<br />• <code>InternalImportsByDefault</code> (SE-0409)<br />• <code>MemberImportVisibility</code> (SE-0444)<br />• <code>NonisolatedNonsendingByDefault</code> (SE-0461)<br /><br />Все четыре флага в <code>swift-list-features</code> помечены <code>language_mode = 7</code><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/main/include/swift/Basic/Features.def#L317\">https://github.com/swiftlang/swift/blob/main/include/swift/Basic/Features.def#L317</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/main/utils/swift-dev-utils/Package.swift#L97C4-L100C62\">https://github.com/swiftlang/swift/blob/main/utils/swift-dev-utils/Package.swift#L97C4-L100C62</a><br /><br /><blockquote>Swift 7 на горизонте, но весьма далеком. Пока довольно примечательный 6.4 приуроченный к даб-дабу.<br /></blockquote><br /><br />@contravariance", "date_published": "2026-05-21T18:54:16+00:00"}, {"id": "https://t.me/c/2068344133/360", "url": "https://t.me/c/2068344133/360", "title": "#compiler #typesystem #swift  Swift 6.4: UniqueBox, Ref &amp; MutableRef. Vol II.  UniqueBox&lt;T&gt", "content_html": "#compiler #typesystem #swift<br /><br /><strong>Swift 6.4: UniqueBox, Ref &amp; MutableRef. Vol II.</strong><br /><br />UniqueBox&lt;T&gt; - unique ownership на хипе без class overhead<br /><br />Мы всегда тривиально могли сделать out of line размещение типа, через class box, но это имеет два менее очевидных недостатка:<br />• Лишний ARC трафик<br />• Shared ownership с потенциальными вытекающими в виде data races<br /><br /><pre><br />    <code class='language-swift'><br />        <br />// ~Copyable: у значения единственный владелец<br />// deinit: явная деструкция ресурса как у class, но без heap-metadata класса<br />public struct UniqueBox&lt;Value: ~Copyable&gt;: ~Copyable {<br />    public init(_ initialValue: consuming Value)<br />    public var value: Value { borrow; mutate }     // SE-0507 non-coroutine accessors<br />    public consuming func consume() -&gt; Value<br />    public func clone() -&gt; UniqueBox&lt;Value&gt;        // только если Value: Copyable<br />}<br />{}<br />    </code><br /></pre><br /><br />Это std::unique_ptr без overhead ARC хедера класса. В отличие от class Box&lt;T&gt;, здесь нет ни retain/release, ни type metadata для полиморфизма - голый UnsafeMutablePointer + deinit в ~Copyable struct. При этом stable address гарантирован: move UniqueBox переносит поинтер, не данные.<br /><br />Практически это означает, например для InlineArray&lt;1024, Float&gt; на стеке с каждым вызовом - code size explosion в caller. UniqueBox&lt;InlineArray&lt;1024, Float&gt;&gt; - одна аллокация, стабильный адрес, возможность взять span и передавать MutableRef.<br /><br />Несколько не очевидных ограничений, которые важно держать в голове при проектировании библиотек:<br />• ~Copyable навсегда меняет resilience границу типа. Если сегодня тип Copyable, а завтра стал ~Copyable - это source-breaking и ABI-breaking (SE-0390). Нет способа сделать это эволюционно без сломанных клиентов. <br />• UniqueBox в public API - это не просто «поместить на heap». Это выбор модели владения, который влияет на:<br />    • возможность использования в Sendable контекстах (условно, через extension UniqueBox: Sendable where Value: Sendable &amp; ~Copyable)<br />    • совместимость с Span/MutableSpan через .span/.mutableSpan<br />    • невозможность случайно скопировать и создать aliasing (именно поэтому ~Copyable)<br />• Ref&lt;T&gt; в stored property требует контейнер ~Escapable. Если добавить Ref как поле в существующий Escapable тип - это source breaking change. Планировать нужно заранее.<br /><br />Примечательно, что можно довольно эргономично расширить все эти <em>коробочки</em> до монаидических, для большей комплиментарности с уже существующими Optional, Result и теми кастомными, что вероятно вы используете - по сути consume() + UniqueBox.init дает ручной способ трансформации в стиле map над ~Copyable.<br /><br />• <a href=\"https://github.com/swiftlang/swift-evolution/blob/main/proposals/0517-uniquebox.md\">SE-0517: UniqueBox</a><br />• <a href=\"https://github.com/swiftlang/swift-evolution/blob/main/proposals/0519-ref-mutableref-types.md\">SE-0519: Ref and MutableRef types for safe, first-class references</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/core/UniqueBox.swift\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/core/UniqueBox.swift</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/core/Ref.swift\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/core/Ref.swift</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.4.x/stdlib/public/core/MutableRef.swift\">/swiftlang/swift/blob/release/6.4.x/stdlib/public/core/MutableRef.swift</a><br />• <a href=\"https://t.me/contravariance/319\">Type Systems: @lifetime dependencies</a><br />• <a href=\"https://t.me/contravariance/346\">Type Systems: Substructural Type Systems. ~Escapable - a quickie</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-05-17T17:39:55+00:00"}, {"id": "https://t.me/c/2068344133/359", "url": "https://t.me/c/2068344133/359", "title": "#compiler #typesystem #swift  Swift 6.4: UniqueBox, Ref &amp; MutableRef. Vol I.  Близится Swift 6.4", "content_html": "#compiler #typesystem #swift<br /><br /><strong>Swift 6.4: UniqueBox, Ref &amp; MutableRef. Vol I.</strong><br /><br />Близится Swift 6.4 - релиз с неочевидной, но принципиальной плотностью. Помимо quality-of-life улучшений concurrency и нескольких долгожданных ABI-инвариантов, выходит пачка типов, которые закрывают давно зиявшую дыру: Swift умел описывать ownership семантически, но не давал инструментов для first-class репрезентации этой семантики в типах.<br /><br />UniqueBox, Ref и MutableRef (formerly Borrow и Inout типы, их переименовали в процессе эволюции) это новые монаидические коробочки для гранулярного управления ownership и безопасного out-of-line размещения value типов.<br /><br />Самое примечательное, что для всего что ниже (оно для Swift 6.4+), есть способ выразить похожие substructual type rules аля вариация scoped affine weakening, но через region based isolation - по сути type system wise dispatch_once. <br /><br />Ref&lt;T&gt; и MutableRef&lt;T&gt;  это не просто “smart pointers” - оба типа ~Escapable. Это не опциональная аннотация - это фундаментальный констрейнт, встроенный в систему типов через lifetime dependency. Я умеренно, но densely писал об этом пару раз минимум <a href=\"https://t.me/contravariance/346\">тут</a> и <a href=\"https://t.me/contravariance/346\">тут</a>. Эти типы не могут покинуть свой lexical scope без явной lifetime аннотации, а значит компилятор статически гарантирует, что dangling reference невозможен - без единого runtime чека.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />// Ref: Copyable &amp; ~Escapable<br />// Несколько одновременных читателей - ок, exclusivity не нарушается<br />public struct Ref&lt;Value: ~Copyable&gt;: Copyable &amp; ~Escapable<br /><br />// MutableRef: ~Copyable &amp; ~Escapable<br />// Единственный “владелец мутации” в каждый момент времени<br />public struct MutableRef&lt;Value: ~Copyable&gt;: ~Copyable &amp; ~Escapable<br />{}<br />    </code><br /></pre><br /><br />Это дословная проекция Swift&#x27;s law of exclusivity в типы. Ref - shared borrow (&amp;T в терминах Rust, но без &#x27;lifetime параметра, заменённого compile-time lifetime dependency). MutableRef - exclusive borrow (&amp;mut T), и оно ~Copyable, потому что два mutable borrow к одному значению - UB по определению.<br /><br />Что довольно примечательно, так это репрезентация Ref&lt;Value&gt; в памяти адаптивно:<br />• Если Value bitwise-borrowable (Int, AnyObject, etc.) и размер ≤ 4 слов - Ref хранит битовую копию значения, не адрес. Иначе - поинтер.<br />• Если Value addressable-for-dependencies (InlineArray, C/C++ типы) - всегда поинтер, чтобы Span, полученный через Ref, мог жить дольше вызова.<br /><br />Это имеет прямые ABI-последствия: Ref&lt;Int&gt; и Ref&lt;InlineArray&lt;512, UInt8&gt;&gt; - разные calling conventions. При проектировании public API, принимающего Ref, нужно понимать, что изменение Value на тип с иной addressability - ABI-breaking change, даже если сигнатура функции формально не меняется.<br /><br />MutableRef этой сложности лишён - inout всегда передаётся по адресу. Напомню, inout - это не передача по ссылке, семантически - это буквально сокращение с copy-in-copy-out -&gt; inout. Часто compiler optimization выдается за семантику, это две разные оси. По этому именно, что по передача по адресу. <br /><br />Продолжение в <strong>Vol II</strong> ниже.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-05-17T17:39:46+00:00"}, {"id": "https://t.me/c/2068344133/358", "url": "https://t.me/c/2068344133/358", "title": "Приглашаю всех завтра на онлайн-стрим, где я и другие инженеры Apple отвечаем на вопросы и делимся п", "content_html": "<blockquote>Приглашаю всех завтра на онлайн-стрим, где я и другие инженеры Apple отвечаем на вопросы и делимся полезными советами по внедрению Swift concurrency в ваш проект!<br /><br /><a href=\"https://t.me/sima_stories\">@sima_stories</a></blockquote><br /><br /><strong>→</strong> <a href=\"https://developer.apple.com/events/view/YFG8A44H89/dashboard?cid=linkedin-social-organic-live-q&amp;a-mwa-swift-concurrency-static-swift-bird-orange-online-sign-up-q3-tue-10am-4-21-2026\"><strong>Регистрация тут</strong></a><br /><br />Вы можете задавать любые вопросы по теме, это отличная возможность!<br /><img src=\"https://tg.davvie.com/static/-1002068344133--358-0.jpg\" alt=\"media\"/>", "date_published": "2026-04-23T04:13:39+00:00", "attachments": [{"url": "https://tg.davvie.com/static/-1002068344133--358-0.jpg", "mime_type": "image/jpeg"}]}, {"id": "https://t.me/c/2068344133/356", "url": "https://t.me/c/2068344133/356", "title": "#compiler #module #swift  Demystifying Module Import: Module Selectors. Vol III. Part II. Compiler M", "content_html": "#compiler #module #swift<br /><br /><strong>Demystifying Module Import: Module Selectors. Vol III. Part II. Compiler Machinery</strong> <strong>II.</strong><br /><br />...<br /><br />Компилятор полностью игнорирует <strong>local lexical shadowing</strong> и сразу достает top level символ из указанного модуля. С обычным dot lookup при коллизии имен всегда выигрывает локальная декларация (переменная с тем же именем что и модуль), что делает код некомпилируемым - селекторы просто иммунны к такому shadowing’у.<br /><br />Но что примечательно, module selector позволят делать extension member disambiguation - с dot lookup просто невозможно лексически выразить (x.Mod::foo()), реэкспорт на уровне lookup деклараций работает, атрибуты и макросы можно квалифицировать(#Mod::macro).<br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\">/swiftlang/swift/blob/release/6.3/lib/Sema/CSGen.cpp#L1457</a><br /><br />А также для T.Foo::Bar в generic context не имеет смысла, потому что ассоциированные типы принадлежат conformance, а не module.<br /><br /><blockquote>Constraints in where clauses also cannot use a module selector to refer to an associated type.</blockquote><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/main/CHANGELOG.md#swift-63\">/swift/blob/main/CHANGELOG.md#swift-63</a><br /><br />В future directions будет выбор conflicting protocol requirements например (там много всего в эволюции добавлено, в пропозале и в ветке форума в дискуссиях есть);<br />Чего селекторы не могут - пока не участвуют в overload resolution для функ типов так, как это делает dot lookup (на <a href=\"https://t.me/contravariance/343\">канале писал подробнее</a>), потому что это строго путь к декларации, а не динамический доступ.<br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/AST/Module.cpp#L1084\">/swiftlang/swift/blob/release/6.3/lib/AST/Module.cpp#L1084</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/CSApply.cpp#L7347\">/swiftlang/swift/blob/release/6.3/lib/Sema/CSApply.cpp#L7347</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/AST/ModuleNameLookup.cpp#L74\">/swiftlang/swift/blob/release/6.3/lib/AST/ModuleNameLookup.cpp#L74</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/AST/UnqualifiedLookup.cpp#L252\">/swiftlang/swift/blob/release/6.3/lib/AST/UnqualifiedLookup.cpp#L252</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\">/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015<br /></a>• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\">/swiftlang/swift/blob/release/6.3/lib/Sema/CSGen.cpp#L1457<br /></a>• <a href=\"http://clang.llvm.org/docs/Modules.html\">clang.llvm.org/docs/Modules.html</a><a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\"><br /></a>• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Import.h\">swift/include/swift/AST/Import.h</a><a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\"><br /></a>• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\">swift-evolution/proposals/0491-module-selectors.md</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-04-11T14:58:18+00:00"}, {"id": "https://t.me/c/2068344133/355", "url": "https://t.me/c/2068344133/355", "title": "#compiler #module #swift  Demystifying Module Import: Module Selectors. Vol III. Part II. Compiler M", "content_html": "#compiler #module #swift<br /><br /><strong>Demystifying Module Import: Module Selectors. Vol III. Part II. Compiler Machinery</strong> <strong>I.</strong> <br /><br />Прошлую часть можно лаконично выразить через:<br /><br />• Module.Member → (Uniform, Variant)  - одна форма, N значений по контексту<br />• Module::Member → (Uniform, Invariant) - одна форма, одно значение везде<br /><br />А теперь посмотрим, как это выглядит в компиляторе:<br /><br /><blockquote>Q: Зачем ввели selective import (::)? Чем он отличается от уже существующего dot-syntax (.)? Напоминает namespace syntax.</blockquote><br /><br />(::) это не namespace аля first class container types, а compile-time name resolution construct для прямого обращения к декларациям в module namespace, минуя обычный lookup pipeline<br /><br /><blockquote>Module selectors are primarily intended to be used when working around unavoidable conflicts, such as when two modules you don&#x27;t control both use the same name. API designs which force clients to use a module selector are not recommended; it is usually better to rename a declaration instead.</blockquote><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/main/CHANGELOG.md#swift-63\">/swift/blob/main/CHANGELOG.md#swift-63</a><br /><br />Dot syntax это member access - компилятор запускает тяжелый многоэтапный поиск (полный пайплайн из ~7 лукапов): сначала unqualified, затем в qualified name lookup.<br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/AST/Module.cpp#L1084\">/swiftlang/swift/blob/release/6.3/lib/AST/Module.cpp#L1084</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/CSApply.cpp#L7347\">/swiftlang/swift/blob/release/6.3/lib/Sema/CSApply.cpp#L7347</a><br /><br /><blockquote>unqualified lookup: local declarations -&gt; parameters -&gt; instance members &lt;= type named выигрывает здесь -&gt; static members &lt;= shadow zone -&gt; module-level decls -&gt; imported module decls -&gt; module names &lt;= module was finally looked up! (Unless shadowed in the previous steps) =&gt; qualified .member lookup<br /></blockquote><br /><br />Module Selector (::) это явный сигнал для name binding по сути прямой qualified лукап или без unqualified lookup и без обхода локальных скоупов e.g. всего пайплайна выше нету. левая часть синтаксически закреплена как module reference и не проходит type/value disambiguation аля “дай мне номинальный тип”. Весь пайплайн сокращается: компилятор скипает локальные скоупы и делает один прямой qualified lookup в глобальном реестре модулей;<br /><br />Можно (грубо) понимать как fully-qualified symbol reference. Design-wise это deterministic name binding + expressivity + dot syntax просто семантически перегружен, это не только module symbol reference, но и type / value / overload / module lookup. Синтаксически типы разделены на module namespace и type/value namespace, а селектор разделяет их лексически. (Это про семантику, но в основном я пишу, о construction machinery);<br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/AST/ModuleNameLookup.cpp#L74\">/swiftlang/swift/blob/release/6.3/lib/AST/ModuleNameLookup.cpp#L74</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/AST/UnqualifiedLookup.cpp#L252\">/swiftlang/swift/blob/release/6.3/lib/AST/UnqualifiedLookup.cpp#L252</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015\">/swiftlang/swift/blob/release/6.3/lib/Sema/TypeCheckAttr.cpp#L3015</a><br /><br /><pre><br />    <code class='language-swift'><br />        <br />import Foundation<br /><br />struct Foundation { }<br /><br />Foundation.URL(string: &quot;https://aboba.net&quot;) // ERROR: Type &#x27;Foundation&#x27; has no member &#x27;URL&#x27;<br />Foundation::URL(string: &quot;https://aboba.net&quot;) // OK: No ambiguity<br />{}<br />    </code><br /></pre><br /><br />Что в эволюции многих системных модулей повлияло на их нейминг (<code>XCTest</code>, <code>Observation</code> etc), а некоторые даже немного читерят под капотом для ambiguity resolution (емнип <code>XCTest</code>);<br /><br />Продолжение во второй части, ниже ↓.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-04-11T14:58:11+00:00"}, {"id": "https://t.me/c/2068344133/354", "url": "https://t.me/c/2068344133/354", "title": "#compiler #module #swift   Demystifying Module Import: Module Selectors. Vol III. Part I. Geometry o", "content_html": "#compiler #module #swift <br /><br /><strong>Demystifying Module Import: Module Selectors. Vol III. Part I. Geometry of Design.<br /></strong><br /><blockquote>• Желательно прочитать <a href=\"https://t.me/contravariance/343\">прошлые</a> две <a href=\"https://t.me/contravariance/344\">части</a> и SE0491, весь контекст с самого начала я не смогу восстановить, вам нужно его держать в голове / знать<br />• После этого все остальное в посте будет очевидно</blockquote><br /><br />В <a href=\"https://t.me/contravariance/344\">прошлой части</a> я написал:<br /><br /><blockquote>В эволюции появились module selectors через SE0491 (пока даже в Swift 6.3 не попадает, фича-гейтится);</blockquote><br /><br />Но это на момент релиза swift-6.3.0-RELEASE уже не правда - module selectors вошли в релиз.<br /><br />Чем они примечательны? Чем отличаются от существующей, на первый взгляд *альтернативы* именуемой, как dot syntax (Module.Member)?<br /><br />Я вам покажу две нетривиальные проекции этих отличий:<br /><br />• <strong>Part I. Geometry of Design</strong>. Desing principles-wise - помогает существенно глубже и качественнее оперировать systems design.<br />• <strong>Part II. Compiler Machinery</strong>. Компиляторная/перф/implementation machinery вкупе с семантической разностью.<br /><br />За дизайном компиляторных решений часто стоят строгие, структурные принципы минимизации информационной энтропии (Shannon entropy): design-wise, селектор униморфен, а dot syntax полиморфен. А структурный принцип, связывающий эти две оси, это <strong>Locality of Source-of-Truth</strong> - способность лексемы нести в себе полноту семантической правды без обращения к внешнему контексту e.g. значение не зависит от того, что находится в скоупе.<br /><br />Униморфность - одна форма, универсальная применимость (applicability). В случае с module selector это унифицированная грамматика во всех позициях, где присутствует type identifier. Один синтаксис, ни одного специального корнер кейса. Синтаксически однороден, но семантически инвариантен. Что дает? - консистентность, предсказуемость, однозначность связи семантики к лексике e.g. fixed 1:1 relationship. Но что еще важнее - механизируемость. Когда семантика инвариантна, инструменты (компилятор, линтер, .swiftinterface генератор) могут механически применять синтаксис без эвристик (подробнее во второй части про compiler machinery).<br /><br /><blockquote>If you maintain a module built with Library Evolution, you can now configure Swift to use module selectors to improve the robustness of its module interface file. This is especially helpful if your module declares a type with the same name as the module itself.</blockquote><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/main/CHANGELOG.md#swift-63\">/swift/blob/main/CHANGELOG.md#swift-63<br /></a><br />Полиморфность - (ортогональна униморфности) одна синтаксическая форма (или интерфейс), но множество семантических интерпретаций. Ортогональноть проявляется в унифицированной грамматике, так же как и с module selectors, но позиционно type identifier может быть полиморфным и быть представлен, как типом так и модулем или быть семантически плотным. Синтаксически однороден, но полиморфен семантически. Один синтаксис, множество специальных корнер кейсов. Что дает? - экспрессивность, контекстуальность, семантическую гибкость к лексике e.g. 1:N relationship.<br /><br />Самые примечательное, что эти две меры можно представить в виде графика и визуально, однозначно провести между ними границу, увидеть ту самую ортогональность явно. Стоит отметить: они не ортогональны друг другу как понятия, но как оси в пространстве дизайна. Это именно тот software design более чистый, более однозначный, без (породоксально) полиморфных трактовок и интерпретаций (dense 1:N relationship). Ось инварианта это ось униморфности, а ось многозначности это полиморфность.<br /><br />Ось X: Semantic variance<br />Invariant (1:1 лексика→семантика) ←→ Variant (1:N)<br /><br />Ось Y: Syntactic cardinality<br />Uniform (одна форма) ←→ Non-uniform (форм N)<br /><br /><blockquote>Тут есть развитие идеи, но оно уходит в моделирование геометрии systems design, сильно за пределами серии постов и формата.</blockquote><br /><br />Это также объясняет, почему все отвергнутые альтернативы из SE-0491 (#Modules.FooKit.bar, @qualified) были хуже: они пытались добавить variant → invariant механизм поверх уже variant синтаксиса, что создавало дополнительный контекст вместо его устранения.<br /><br />Два строгих, определенных и структурно однозначных принципа лежащих в разных, но взаимно дополняющих плоскостях.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-04-11T14:58:04+00:00"}, {"id": "https://t.me/c/2068344133/353", "url": "https://t.me/c/2068344133/353", "title": "[FATAL ERROR]: Rendering Pipeline Halted com.apple.iokit.IOGraphicsFamily → kIOReturnOverrun (0xBAAD", "content_html": "<strong>[FATAL ERROR]: Rendering Pipeline Halted<br /></strong>com.apple.iokit.IOGraphicsFamily → kIOReturnOverrun (0xBAADF00D).<br /><br /><strong>The XNU scheduler has intercepted an illegal operation. The technical overhead of this post has triggered a kIOGPUCommandBufferCallbackErrorTimeout (0xDEADBEEF), as the shader complexity reached a computational cost of O(nⁿ).<br /><br />Resolution</strong>: This post requires an out-of-band firmware patch and a more efficient Metal shading language abstraction before it can safely reach the frame buffer.<br /><br />(простите :D)", "date_published": "2026-04-01T07:29:25+00:00"}, {"id": "https://t.me/c/2068344133/351", "url": "https://t.me/c/2068344133/351", "title": "#typesystems #constraintsolver #polymorpshism  Type System: Substructural Polymorphism &amp; Overloa", "content_html": "#typesystems #constraintsolver #polymorpshism<br /><br /><strong>Type System: Substructural Polymorphism &amp; Overload Resolution. Vol II</strong>I<strong>: ~Escapable, ~Copyable, </strong><strong>@lifetime</strong><strong>, SIL Ownership &amp; Structural Polymorphism</strong><br /><br />Для полного контекста просьба прочитать по порядку:<br />• <a href=\"https://t.me/contravariance/346\">Type Systems: Substructural Type Systems. ~Escapable - a quickie.</a><br />• <a href=\"https://t.me/contravariance/346?comment=746\">Коммент Макса @maximkrouk<br /></a>• <a href=\"https://t.me/contravariance/350\">Type System: Substructural Polymorphism &amp; Overload Resolution. Vol II: ~Escapable, ~Copyable, @lifetime, SIL Ownership &amp; Structural Polymorphism</a><br /><br /><blockquote>Но как я понимаю для ~Copiable ~Escapable должны генериться отдельные функции?</blockquote><br /><br />Copyable типы могут передаваться через vtable / witness tables - компилятор знает, как их копировать и уничтожать по умолчанию. Но для ~Copyable компилятор должен гарантировать unique ownership. То есть он не может использовать стандартные generic thunks, которые по умолчанию делают retain/release. <br />C ~Escapable ситуация еще примечательнее: поскольку такой тип stack-bound, его нельзя просто упаковать в Any или передать в абстрактный контейнер без потери информации о lifetime / lifetime depeйndenceis.<br /><br />В SIL calling conventions для обычных Copyable дженериков - @in (owned, caller передаёт ownership) и @out (indirect result). Для ~Copyable картина принципиально другая: borrowed параметры идут как @in_guaranteed (caller гарантирует lifetime, callee не владеет), consumed - как @owned (transfer ownership, callee обязан destroy или forward). Это разные ownership transfer semantics на уровне SIL, что означает разные destructor insertion points и разный lifetime analysis path в SILGen.<br /><br />Для ~Escapable с lifetime dependencies добавляется mark_dependence - это SIL instruction которая буквально кодирует ребро в dependency графе: mark_dependence %value on %base говорит что %value не может outlive %base. Это не аннотация, а операнд в dataflow - verifier проверяет что зависимость не нарушена, а optimizer не может переупорядочить или элиминировать код через эту границу.<br /><br />Как итог - structural polymorphism здесь невозможен не абстрактно, а конкретно: generic thunk для Copyable типа делает retain/release по умолчанию, тогда как для ~Copyable такой thunk был бы некорректен по построению - он нарушил бы unique ownership инвариант. А mark_dependence вообще не имеет аналога в Copyable мире - это принципиально другой IR, не совместимый структурно.<br /><br />Переход в nominal subtyping аля (у Макса, что то в этом духе):<br /><br /><pre><br />    <code class='language-swift'><br />        <br />enum Effects { … }<br /><br />struct Pipe&lt;Input, Output, Effect&gt; {<br />    let run: (Input) -&gt; Output<br />    func callAsFunction(_ x: Input) -&gt; Output { run(x) }<br />}<br /><br />// Морфизмы явно определены через conformances<br />extension Pipe: Swift.Sendable <br />    where Effect == Effects.Sendable, <br />          Input: Swift.Sendable, <br />          Output: Swift.Sendable {}<br /><br />// Композиция - nominal, solver видит конкретные type witnesses<br />func &lt;&lt;&lt; &lt;A, B, C, E&gt;(<br />    _ f: Pipe&lt;B, C, E&gt;,<br />    _ g: Pipe&lt;A, B, E&gt;<br />) -&gt; Pipe&lt;A, C, E&gt; {<br />    Pipe { f(g($0)) }<br />}<br />{}<br />    </code><br /></pre><br /><br />По сути единственный легальный escape hatch (не конкретно implementation-wise, а структурно) - типизированный способ дать солверу конкретные правила ранжирования - переход неявных, неопределенных морфизмов, к явным type witnesses. <br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L3414\">/swift/blob/release/6.3/include/swift/AST/Types.h#L3414 → AnyFunctionType</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L4027\">/swift/blob/release/6.3/include/swift/AST/Types.h#L4027 → FunctionType</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L4141\">/swift/blob/release/6.3/include/swift/AST/Types.h#L4141 → ParameterListInfo</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L4202\">/swift/blob/release/6.3/include/swift/AST/Types.h#L4202 → GenericFunctionType</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L2497\">/swift/blob/release/6.3/include/swift/AST/Types.h#L2497 → ParameterTypeFlags</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/CSRanking.cpp\">/swift/blob/release/6.3/lib/Sema/CSRanking.cpp</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/CSSimplify.cpp\">/swift/blob/release/6.3/lib/Sema/CSSimplify.cpp</a><br />• <a href=\"https://github.com/swiftlang/swift-evolution/blob/9b600fe6c847e7e0a84009acc079a99ff5786ffb/proposals/NNNN-lifetime-dependency.md#function-type-syntax\">/swift-evolution/lifetime-dependencies.md#function-type-syntax</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/0e0731b28c05395c48ef92f8ff99f4bdcf2f49a8/include/swift/Sema/Score.h#L23\">/swift/.../include/swift/Sema/Score.h#L23</a> (в Swift 6.3 начался серьезный re-engineering constraint solver’a)<br />• <a href=\"https://github.com/capturecontext/swift-capture\">/github.com/capturecontext/swift-capture</a> (репозиторий @maximkrouk рекомендую к ознокомлению)<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-03-27T15:47:51+00:00"}, {"id": "https://t.me/c/2068344133/350", "url": "https://t.me/c/2068344133/350", "title": "#typesystems #constraintsolver #polymorpshism  Type System: Substructural Polymorphism &amp; Overloa", "content_html": "#typesystems #constraintsolver #polymorpshism<br /><br /><strong>Type System: Substructural Polymorphism &amp; Overload Resolution. Vol II: ~Escapable, ~Copyable, </strong><strong>@lifetime</strong><strong>, SIL Ownership &amp; Structural Polymorphism</strong><br /><br />Для полного контекста просьба прочитать по порядку:<br />• <a href=\"https://t.me/contravariance/346\">Type Systems: Substructural Type Systems. ~Escapable - a quickie.</a><br />• <a href=\"https://t.me/contravariance/346?comment=746\">Коммент Макса @maximkrouk<br /></a>• <a href=\"https://t.me/contravariance/349\">Type System: Substructural Polymorphism &amp; Overload Resolution. Vol I: When Structural Polymorphism Breaks the Solver</a><br /><br />Но если C: ~Escapable - тогда нужно пробросить lifetime chain A → B → C через composition, и тут возникает вопрос: как выразить lifetime в типе возвращаемого функ типа?<br /><br /><pre><br />    <code class='language-swift'><br />        <br />@lifetime(borrow 0) // result depends on argument A <br />func &lt;&lt;&lt; &lt;A, B: ~Escapable, C: ~Escapable&gt;( <br />    _ b2c: (borrowing B) -&gt; C, // @lifetime(borrow 0)? <br />    _ a2b: (A) -&gt; B // @lifetime(borrow 0)? <br />) -&gt; @lifetime(borrow ???) (A) -&gt; C {<br />    …<br />}<br />{}<br />    </code><br /></pre><br /><br />Это все еще открытый вопрос в текущем дизайне lifetime annotations, дизайн перегрузок будет зависеть того как останутся ли lifetime dependenceis as name-based dependency или же все таки заимплементят positional dependencies - но это даже в первую финальную итерацию не попадает. Можно будет так задизайнить dependencies, чтобы комбинаторный взрыв возможных subtype версий был разрешим, но в дженерик случае это неразрешимая задача - tentative ranking либо решит однозначно и выведет score, либо будет наш любимый type ambiguity error.<br /><br />При composition f &lt;&lt;&lt; g dependency граф результата зависит от внутренней структуры обеих функций одновременно, и solver не имеет доступа к этой информации на уровне типов - она стёрта в сигнатуре. А dependency графы при composition не compositional в общем случае, что и делает однозначный ranking принципиально невозможным без дополнительных constraints. <br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/CSRanking.cpp\">/swift/blob/release/6.3/lib/Sema/CSRanking.cpp</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Sema/CSSimplify.cpp\">/swift/blob/release/6.3/lib/Sema/CSSimplify.cpp</a><br />• <a href=\"https://github.com/swiftlang/swift-evolution/blob/9b600fe6c847e7e0a84009acc079a99ff5786ffb/proposals/NNNN-lifetime-dependency.md#function-type-syntax\">/swift-evolution/lifetime-dependencies.md#function-type-syntax<br /></a><br />Но они все равно не влияют на structural subtype identity - то есть это такой же declaration attribute как @Sendable, @AnyGlobalActor, @isolated(any) etc. Хотя для них формально определены морфизмы на AST уровне. Для эффектов добавляется overload discrimination для ambiguity resolution в виде того самого tentative ranking’a. <br /><br /><pre><br />    <code class='language-h'><br />        <br />/// Describes an aspect of a solution that affects its overall score, i.e., a<br />/// user-defined conversions.<br />enum ScoreKind {<br />  …<br />  SK_Unavailable,          // использование deprecated/unavailable<br />  SK_Fix,                  // потребовалось исправление<br />  SK_UnresolvedMember,<br />  SK_ForceUnchecked,       // as!<br />  SK_UserConversion,       // пользовательская конверсия<br />  SK_FunctionConversion,   // конверсия функционального типа &lt;- that’s what we look for<br />  SK_NonDefaultLiteral,<br />  SK_ImplicitValueConversion,<br />  ...<br />}<br />{}<br />    </code><br /></pre><br /><br />SK_FunctionConversion инкрементируется при каждом implicit function type coercion. Решение с меньшим score - доминирует.<br /><br />Для throws / async:<br /><pre><br />    <code class='language-'><br />        <br />sync -&gt; async:      +1 SK_FunctionConversion<br />non-throws -&gt; throws: +1 SK_FunctionConversion<br />{}<br />    </code><br /></pre><br /><br />Точное совпадение +0. Поэтому async overload при async аргументе всегда побеждает - меньший score.<br /><br />Для @Sendable:<br /><pre><br />    <code class='language-'><br />        <br />@Sendable -&gt; plain:  +1 SK_FunctionConversion  (ослабление constraint)<br />@Sendable -&gt; @Sendable: +0<br />{}<br />    </code><br /></pre><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/0e0731b28c05395c48ef92f8ff99f4bdcf2f49a8/include/swift/Sema/Score.h#L23\">/swift/.../include/swift/Sema/Score.h#L23</a> (в Swift 6.3 начался серьезный re-engineering constraint solver’a)<br /><br /><pre><br />    <code class='language-h'><br />        <br />enum ScoreKind: unsigned int {<br />  // These values are used as indices into a Score value.<br /><br />  /// A fix needs to be applied to the source.<br />  SK_Fix,<br />  /// A hole in the constraint system.<br />  SK_Hole,<br />  /// A reference to an @unavailable declaration.<br />  SK_Unavailable,<br />  /// A reference to a declaration from a module that has not been imported.<br />  SK_MissingImport,<br />  /// A reference to an async function in a synchronous context.<br />  ///<br />  /// \\note Any score kind after this is considered a conversion that doesn&#x27;t<br />  /// require fixing the source and will be ignored during code completion.<br />  SK_AsyncInSyncMismatch,<br />…<br />}<br />{}<br />    </code><br /></pre><br /><br />Продолжение с третьей части.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-03-27T15:47:41+00:00"}, {"id": "https://t.me/c/2068344133/349", "url": "https://t.me/c/2068344133/349", "title": "#typesystems #constraintsolver #polymorpshism  Type System: Substructural Polymorphism &amp; Overloa", "content_html": "#typesystems #constraintsolver #polymorpshism<br /><br /><strong>Type System: Substructural Polymorphism &amp; Overload Resolution. Vol I: When Structural Polymorphism Breaks the Solver</strong><br /><br />Для полного контекста просьба прочитать по порядку:<br />• <a href=\"https://t.me/contravariance/346\">Type Systems: Substructural Type Systems. ~Escapable - a quickie.</a><br />• <a href=\"https://t.me/contravariance/346?comment=746\">Коммент Макса @maximkrouk<br /></a><br />Проблема с перегрузками операторов композиции (&lt;&lt;&lt;) - а тут функ тип полиморфного вида (polymorphic function type kind, всего из два вида - non-generic мономорфный) пораждает комбинаторный взрыв при @Sendable (+других атрибутах, даже @isolated(any) - это весьма примечательный атрибут статически стирающий изоляцию, но в рантайме позволяющий ее восстановить через (any Actor)? - runtime witness) (точечная попытка внести runtime polymorphism в мир эффектов, но для overloading’a это еще одно измерение комбинаторного взрыва - как комбинировать изоляцию MainActor &lt;&lt;&lt; any Actor (?)), эффекты - subtype polymorphism не effectful, а lifetime атрибуты вообще не участвуют в формировании сигнатуры функ типа. <br /><br /><pre><br />    <code class='language-h'><br />        <br />/// AnyFunctionType - A function type has zero or more input parameters and a<br />/// single result. The result type may be a tuple. For example:<br />///   &quot;(int) -&gt; int&quot; or &quot;(a : int, b : int) -&gt; (int, int)&quot;.<br />///<br />/// There are two kinds of function types:  monomorphic (FunctionType) and<br />/// polymorphic (GenericFunctionType). Both type families additionally can<br />/// be &#x27;thin&#x27;, indicating that a function value has no capture context and can be<br />/// represented at the binary level as a single function pointer.<br />class AnyFunctionType : public TypeBase {<br />  const Type Output;<br />  uint16_t NumParams;<br />…<br />{}<br />    </code><br /></pre><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L3414\">/swift/blob/release/6.3/include/swift/AST/Types.h#L3414 → AnyFunctionType</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L4027\">/swift/blob/release/6.3/include/swift/AST/Types.h#L4027 → FunctionType</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L4141\">/swift/blob/release/6.3/include/swift/AST/Types.h#L4141 → ParameterListInfo</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L4202\">/swift/blob/release/6.3/include/swift/AST/Types.h#L4202 → GenericFunctionType</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Types.h#L2497\">/swift/blob/release/6.3/include/swift/AST/Types.h#L2497 → ParameterTypeFlags<br /></a><br />То есть, когда overload resolution и constraint solver пытаются сопоставить сигнатуры f &lt;&lt;&lt; g то ранкинг посчитает одинаковые очки, а subtyping для Sendable функ типа это подтип обычного, plain - функ типа. Опять же tentative ranking не сможет посчитать ранк и финальный score будет эквивалентен, а это прямой путь к “ambiguous use of operator”.<br /><br />В Swift есть генерализированный nominal subtyping, но отсутствует генерализированными subtype, effect - structural polymorhism. Все что есть в качестве поддержки subtype polymorphism это некоторая форма coercion или неявного приведения, через type witness с формально определенными категориальными морфизмами:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />let f: @isolated(any) (Int) -&gt; Int = { $0 }<br />let g: nonisolated(nonsending) (Int) async -&gt; Int = f<br />{}<br />    </code><br /></pre> <br /><br />Workaround c <code>callAsFunction</code> - идиоматичный и по сути смещает плоскость полиморфизма со структурной, на номинальную - то есть плоскости неопределенных подструктурных правил tentative ranking’a overload resolution constraint solver’a - к номинальным типам, где поструктурные правила формально выводимы. <br /><br />С @lifetime атрибутами есть некоторые приколы: <br /><br /><pre><br />    <code class='language-swift'><br />        <br />@lifetime(???)<br />func &lt;&lt;&lt; &lt;A, B: ~Escapable, C&gt;(<br />    _ b2c: @lifetime(borrow ???) (borrowing B) -&gt; C,<br />    _ a2b: @lifetime(???) (borrowing A) -&gt; B<br />) -&gt; (A) -&gt; C<br />{}<br />    </code><br /></pre><br /><br />Проблема в том, что в теле замыкания:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />{ a in<br />    let b = a2b(a)  // b: B (~Escapable), depends on a<br />    return b2c(b)   // b borrowed by b2c, C returned<br />}  // b destroyed here<br />{}<br />    </code><br /></pre><br /><br />Если C: Escapable, то всё работает - b живёт и умирает внутри замыкания, C не несёт lifetime dependency. Тип функции @lifetime-аннотации не нужны на closure type level.<br /><br />Продолжение во второй части.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-03-27T15:47:29+00:00"}, {"id": "https://t.me/c/2068344133/348", "url": "https://t.me/c/2068344133/348", "title": "С парочкой приватных CoreAnimation layers вкупе с allowsBackdropGroups и forwardsClientHitTestingToS", "content_html": "<blockquote>С парочкой приватных CoreAnimation layers вкупе с <strong><em>allowsBackdropGroups</em></strong> и <strong><em>forwardsClientHitTestingToSourceView</em></strong> (CABackdropLayer, _UIPortalView) - можно делать весьма примечательные вещи. Эти билдинг блоки раскиданы по всему UI-стеку практически каждой Apple OS.</blockquote><br /> <br />Очень радует глубина материала и сам факт того, что новые люди в нашем инженерном паблик спейсе делятся топ контентом! <br /><br />Это мой вклад в общее дело и надеюсь вы так же поддержите Сергея! <br /><br />Канал Сергея: @lazy_var<br /><br />@contravariance", "date_published": "2026-03-21T14:25:02+00:00"}, {"id": "https://t.me/c/2068344133/347", "url": "https://t.me/c/2068344133/347", "title": "_UIPortalView - репликация view без копирования и снапшотов   Сталкивались с ситуацией, когда необхо", "content_html": "<a href=\"https://github.com/nst/iOS-Runtime-Headers/blob/master/PrivateFrameworks/UIKitCore.framework/_UIPortalView.h\"><strong>_UIPortalView</strong></a><strong> - репликация view без копирования и снапшотов</strong> <br /><br />Сталкивались с ситуацией, когда необходимо показать содержимое одной view в другом месте экрана? Например, живая миниатюра контента (PiP), отражение, размытый backdrop или копия view для hero-transition.<br />Вариантов обычно два:<br />1. Дублировать объект - создать полную копию с вложенной иерархией, синхронизировать состояние, управлять жизненным циклом.<br />2. Рендерить snapshot каждый кадр через drawHierarchy или snapshotView.<br />Оба варианта жизнеспособны, но первый даёт усложнение, а второй нагрузку на CPU.<br /><br />У Apple есть приватное API _UIPortalView, которое решает эту задачу на уровне системного композитора.<br /><blockquote>В iOS 26 _UIPortalView стал частью <a href=\"https://x.com/SebJVidal/status/1932184648567947553\">_UILiquidLensView</a> - приватного компонента, который реализует Liquid Glass.</blockquote><br /><br /><br /><strong>Как это работает?</strong><br /><strong>_UIPortalView</strong> это UIView, чей backing layer <a href=\"https://aditya.vaidyam.me/blog/2018/02/18/\">CAPortalLayer.</a> CAPortalLayer хранит ссылку (sourceLayerRenderId) на source layer в render tree и говорит render server композитить содержимое source в позиции портала. _UIPortalView добавляет UIKit-уровень: sourceView вместо sourceLayerRenderId, matchesPosition, matchesAlpha и другие свойства.<br /><br /><br /><strong>Как получить доступ?</strong><br />Класс приватный - доступ через runtime:<br /><pre><br />    <code class='language-objective-c'><br />        <br />Class cls = NSClassFromString(@&quot;_UIPortalView&quot;);<br />UIView *portal = [[cls alloc] init];<br />{}<br />    </code><br /></pre><br /><br /><br /><strong>Доступные свойства</strong><br /><strong><em>sourceView</em></strong> — vew-источник, контент которого отображает портал<br /><strong><em>matchesPosition</em></strong> — привязка к позиции source в координатах окна<br /><strong><em>matchesTransform</em></strong> — наследует transform от source<br /><strong><em>matchesAlpha</em></strong> — наследует alpha от source<br /><strong><em>hidesSourceView</em></strong> — скрывает source, но порталы его отображают<br /><strong><em>allowsHitTesting</em></strong> — разрешает hit testing на портале<br /><strong><em>allowsBackdropGroups</em></strong> — поддержка CABackdropLayer групп (blur/vibrancy)<br /><strong><em>forwardsClientHitTestingToSourceView</em></strong> — пробрасывает тачи с портала на source<br /><br /><br /><strong>Как работает matchesPosition?</strong><br />• <strong>matchesPosition = true</strong> - портал показывает фрагмент source, совпадающий по позиции в координатах окна. Как отверстие в стене, за которой спрятан source (именно так работает эффект <a href=\"https://github.com/TelegramMessenger/Telegram-iOS/blob/master/submodules/WallpaperBackgroundNode/Sources/WallpaperBackgroundNode.swift\">градиентного фона</a> у баблов сообщений в Telegram - каждый бабл показывает свой кусок одного общего градиента)<br />• <strong>matchesPosition = false</strong> - портал показывает source от (0, 0). Управлять видимой областью можно через bounds.origin портала (сдвиг viewport) или через frame.origin портала внутри clipped-контейнера.<br /><br /><br /><strong>Перформанс</strong><br />Поскольку рендеринг происходит в render server, создание порталов практически не увеличивает нагрузку на CPU. <br />Но есть нюансы при большом количестве порталов - GPU накладывает свои ограничения, но об этом расскажу отдельно.<br /><br /><blockquote>Когда попробовал порталировать AVPlayerLayer, столкнулся с тем, что в портале отображался застывший кадр - портал обновлялся только при изменении layer-свойства в source subtree.<br /><br />Причина: AVPlayerLayer.contents обновляется через IOSurface swap. CAPortalLayer подписан на изменения layer tree (transform, opacity, sublayers), а не на IOSurface content changes внутри source subtree. <br />Workaround - infinite анимация на source sublayer, которая поднимает dirty flag каждый кадр.<br /><br />Спасибо @eleev за пояснение.</blockquote><br /><br />В следующих статьях расскажу подробней про ограничения, производительность и хитрые способы применения.<br /><video controls poster=\"https://tg.davvie.com/static/-1002068344133--347-0.mp4\" style=\"max-width:100%;\"><source src=\"https://tg.davvie.com/static/-1002068344133--347-0.mp4\" type=\"video/mp4\">Your browser does not support the video tag.</video>", "date_published": "2026-03-21T14:24:12+00:00", "attachments": [{"url": "https://tg.davvie.com/static/-1002068344133--347-0.mp4", "mime_type": "video/mp4"}]}, {"id": "https://t.me/c/2068344133/346", "url": "https://t.me/c/2068344133/346", "title": "#typesystems #swift #ownership  Type Systems: Substructural Type Systems. ~Escapable - a quickie.  Н", "content_html": "#typesystems #swift #ownership<br /><br /><strong>Type Systems: Substructural Type Systems. ~Escapable - a quickie.</strong><br /><br />Некоторые из предыдущий частей из серии системы типов Swift (на канале +25 постов на эту тему):<br /><br />• <a href=\"https://t.me/contravariance/199\">Swift Evolution: ~Escapable<br />•</a> <a href=\"https://t.me/contravariance/322\">Type System: Many Faces of Type Witness</a><br />• <a href=\"https://t.me/contravariance/323\">Type System: Conformance Substitution &amp; Projection</a><br />• <a href=\"https://t.me/contravariance/319\">Type Systems: @lifetime dependencies</a><br /><br />Этот же пост - ультра короткая и максимально нишевая, densly-packed заметка для ценителей систем типов, category theory, если вы видите морфизмы в конструкциях языка и в какой то момент вам стало максимально прозрачно, что монада это моноид из категории эндофункторов - то welcome (из вас есть минимум 8 человек, кто неравнодушен к этому, ухуу). <br /><br /><blockquote>Я знаю, вам нейро-слоп надоел, поэтому это все так же 110% hand-crafted, ультра-душная заметка.</blockquote><br /><br />Звучит довольно теоретически, до тех пора, пока … long story short ну это не совсем теория в итоге. Кто дальше теории не видит - <strong>¯\\_(ツ)_/¯. </strong>А компилятор так устроен, что вы этим всем пользуется да в такой манере, что об этом можно совсем не подозревать. Но стоит лишь тривиально мапнуть опционал;<br /><br />…<br /><br />Один playground-сниппет, а сколько богатства под капотом [swift-6.2.3-RELEASE -enable-experimental-feature Lifetimes]:<br /><br />• Substrutal type-systems где по сути конструируется Kleisli монада<br />• Обычные типы живут в cartesian category - substructural же в symmetric monadical closed category <br />• В классических системах присутствуют 3 основных подструктурных правила типов: <br />   • Weakening (если тривиально, когда переменная может игнорироваться)<br />   • Contraction  (когда она уже может использоваться +1 раз)<br />   • Exchange (когда она может быть re-assigned)<br />• В affine type system - contraction отсуствует - то есть инстанс типа / значение может быть использовано at most once<br />• В linear - exactly once <br />• ~Copyable - это вариация affine subtyping <br />• А ~Copyable + ~Escapable + lifetime - scoped affine, где weakening разрешен, но в рамках лексического скоупа<br /><br />А теперь карманный микро-плейграунд в вакууме: структурно ограничим токен с зависимостями на лексический скоуп:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />@_lifetime(borrow lhs, borrow rhs)<br />func comparator&lt;T: ~Escapable&gt;(<br />  _ lhs: T,<br />  _ rhs: T,<br />  by precedes: (T, T) -&gt; Bool<br />) -&gt; T {<br />  precedes(lhs, rhs) ? lhs : rhs<br />}<br /><br />struct Token: ~Escapable {<br />  @_lifetime(immortal)<br />  init() {}<br />}<br /><br />@_lifetime(immortal)<br />func makeToken() -&gt; Token {<br />  Token()<br />}<br /><br />@_lifetime(borrow val)<br />func consume(_ val: some ~Escapable) {<br />  dump(type(of: val))<br />}<br /><br />let lhs = makeToken()<br />let auth: Token<br />do {<br />  let rhs = makeToken()<br />  auth = comparator(lhs, rhs, by: { … })<br />  // auth depends on BOTH lhs and rhs<br />  _ = result<br />} // rhs dies here (~)<br /><br />consume(auth)  // ERROR: we cannot use auth token, since its lifetime ended in do scope<br />{}<br />    </code><br /></pre><br /><br />А это лишь начало: можно будет скоупить @escaping замыкания с промоушеном на стек и описывать output dependencies. Скоупить, ограничивать ownership, промоутать на стек - малая часть дизайн-юзкейсов. Раньше чем в Swift 6.4 - Swift 6.6 не появится. Беспокоиться тоже не стоит - это все progressive disclosure complaint эволюция.<br /><br />А в одном из постов я покажу, как минимизировать хопы между акторами (хопы внутри cooperative thread pool - дешевы, но вот outside thread pool хопы - другая история e.g. custom executors, pinned tasks, main actor etc) и вообще решить класс проблем пересечения disconnected isolation regions сугубо через ownership и систему типов. Та малая часть материала, где про то, как уродуют API surface инжектя isolation domain (который может быть не доступен для модификации) - можно в ряде случаем решать на стороне вызывающего кода / клиента и только средствами системы типов + region based analysis. <br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-02-25T18:40:09+00:00"}, {"id": "https://t.me/c/2068344133/344", "url": "https://t.me/c/2068344133/344", "title": "#swift #compiler #modules  Demystifying Module Import: Selective Import &amp; Compiler. Vol II.  Sel", "content_html": "#swift #compiler #modules<br /><br /><strong>Demystifying Module Import: Selective Import &amp; Compiler</strong>. <strong>Vol I</strong>I.<br /><br />Selective import так же (очевидно) не повлияет никак на импорт clang-related (c/objective c) символы / модули и будет способствовать так называемого clang importer pass’у - дополнительного компиляционного паса для экспорта в соотвествующие Swift API, так как результирующий AST может быть представлен в обязательном пасе семантического анализа. Все это резолвится до SIL, не покидая фронтенд;<br /><br /><blockquote>Исторически Cocoa любит (?!) umbrella фреймворки, чем UIKit по сути архитектурно и является, импортнуть CoreAnimation не получится сам по себе (ибо подмодуль QuartzCore), но отдельные декларации - можно import class UIKit.CALayer или CoreServices.DictionaryServices;</blockquote><br /><br />А теперь добавляем ко всему этому пару компиляторных примечательностей #1: если связность символов внутри импортируемого модуля в процессе ленивой резолюции (lazy module deserialization resolution, lib/Serialization/ModuleFile.h) плотная, то произойдет каскадный взрыв пораждающий рекурсивный резолюшен всех необходимых символов. В таком, практически не контролируемом случае, модуль будет полностью импортирован и влияние именно, что на производительность (ни runtime, ни compiletime, ни тем более buildtime) будет около нулевым (холодный buildtime напротив скорее всего увеличится). Вместо частичного импорта, ASTContext заполняется почти всеми данными из .swiftmodule, что делает потребление памяти сопоставимым с полным импортом, а рекурсивный резолюшен заставляет type checker выполнять работу в объеме, близком к обработке всего интерфейса модуля. <br /><br />Какая общая и весьма абстрактная рекомендация? - Разделять на более мелкие модули с низкой связностью. Важно помнить, что Swift задизайнен через progressive disclosure - то есть наличие отдельно взятой функциональности не обязательно является серебряной пулей, важен контекст применения и трейдофф, который чаще всего придется заплатить;<br /><br />Примечательно #2 и #3:<br />• В эволюции появились module selectors через SE0491 (пока даже в Swift 6.3 не попадает, фича-гейтится);<br />• В сlang это с давних времен (десятилетиями?) в objc / c активно юзается, называется сlang module maps, юзается для header-based modularization. Swift перенял модель, но усложнил (расширил?) ее дженериками, добавил overload resolution и protocol extensions (тут еще что то есть, надо смотреть);<br /><br />Примечательно #4:<br />В компиляторе в AST декларациях модуля (include/swift/AST/Import.h), импорта и типа импорта есть много причательностей. Одна из них:<br /><br /><pre><br />    <code class='language-cpp'><br />        <br />/// Describes what kind of name is being imported.<br />///<br />/// If the enumerators here are changed, make sure to update all diagnostics<br />/// using ImportKind as a select index.<br />enum class ImportKind : uint8_t {<br />  Module = 0,<br />  Type,<br />  Struct,<br />  Class,<br />  Enum,<br />  Protocol,<br />  Var,<br />  Func<br />};<br />{}<br />    </code><br /></pre><br /><br />Акторы импортируется через class kind - ибо для них нет отдельного import типа; То есть следующий явный, selective import для Main Actor валиден на момент Swift 6.3 (пример в вакууме):<br /><br /><pre><br />    <code class='language-swift'><br />        <br />import class _Concurrency.MainActor<br />{}<br />    </code><br /></pre><br /><br />На фронтенде компилятора актор (actor type) - как такового не существует, есть лишь тип класс (class type) с особыми метаданными и флагами, которые в процессе материализуются (SIL gen) в тип актор;<br /><br /><blockquote>Актор это не просто final class (~&gt; AnyActor ~&gt; AnyObject &amp; Actor (Sendable)) - а имплементационно concurrent CAS state machine over serial executor, с набором примечательностей (парочку таких я <a href=\"https://t.me/contravariance/326\">в меру глубоко разбирал тут</a>).</blockquote><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/main/docs/Modules.md\">swift/docs/Modules.md</a><br />• <a href=\"http://clang.llvm.org/docs/Modules.html\">clang.llvm.org/docs/Modules.html</a><br />• <a href=\"https://github.com/swiftlang/swift-evolution/blob/main/proposals/0491-module-selectors.md\">swift-evolution/proposals/0491-module-selectors.md</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/AST/Import.h\">swift/include/swift/AST/Import.h</a><br />• <a href=\"https://github.com/swiftlang/swift/tree/release/6.3/lib/ClangImporter\">swift/lib/ClangImporter</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/lib/Serialization/ModuleFileSharedCore.h\">swift/lib/Serialization/ModuleFileSharedCore.h</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/Serialization/Validation.h\">swift/include/swift/Serialization/Validation.h</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.3/include/swift/Serialization/SerializedModuleLoader.h\">swift/include/swift/Serialization/SerializedModuleLoader.h</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-01-19T15:07:59+00:00"}, {"id": "https://t.me/c/2068344133/343", "url": "https://t.me/c/2068344133/343", "title": "#swift #compiler #modules  Demystifying Module Import: Selective Import &amp; Compiler. Vol I.  Q: i", "content_html": "#swift #compiler #modules<br /><br /><strong>Demystifying Module Import: Selective Import &amp; Compiler</strong>. <strong>Vol I</strong>.<br /><br /><blockquote>Q: import var/let/struct/class влияет ли на перформанс? Если да, то сильно ли? Стоит ли импортить что-то конкретно из библиотеки вместо цельного импорта?</blockquote><br /><br />Вопрос хороший (спасибо @signal_SIGABRT), попробую на него ответить так, чтобы в <del>один</del> два телеграмных поста уместился.<br /><br />В целом именно на перф не сильно влияет, но сказать “не сильно” по хорошему будет не корректно - надо замерять (перф? - runtime (почти всегда нет)? binary size (нет)? compile time ? - может и влиять (дальше разверну почему и когда)). В доках компилятора сами инженеры написали, что не замеряли (емнип) на более или менее вменяемых кодобазах. Можно читать как: зависит от размера пакета, связности символов внутри модуля, плотности overload sets - ибо если это импорт несвязной функции, то все ее оверлоады так же подтянутся (SIL генерируется только для реально выбранной overload’а, остальные могут остаться purely semantic), но если импортируемый символ тянет за собой граф - то это совсем другая ситуация; Замерить это так чтобы получить внятные прикладные цифры не самое просто дело;<br /><br /><blockquote>Важно понимать, что import влияет на: semantic analysis, name lookup, type checking, dependency graph - перформанс это размытое понятие, зависит от системы измерения / метрик, куда весомее влияние на тайп чекер и резолвинг символов (об это чуть развернутее ниже);</blockquote><br /><br />Есть важное но (!): импорт декларации (формально selective import) это не обязательно именно про перф - можно разрешать коллизии импорта, так как приоритет разрешения символа у типа над модулем разный (через полный qualified name resolution), а так же в некоторых прям редких случаях разрешать коллизии в случае если имена модулей идентичные.<br /><br />Любая декларация в модуле всегда уникальная (declaration mangled module name) Уникальность обеспечивается за счет mangled name, module identity, linkage context. То есть module import это больше про semantic analysis, name lookup, type checking, dependency graph etc:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />UIKit.CALayer<br />QuartzCore.CALayer<br />{}<br />    </code><br /></pre><br /><br />Очевидно это разные символы, даже если API совпадает;<br /><br />Qualified и unqualified name lookup - если просто, можно понимать как резолвинг идентификаторов деклараций. Qualified - для именованных деклараций, unqualified - относительно лексического + source location где идентификатор встречается (импорт и разрешение name lookup тесно связны в этом контексте) (по мимо этого есть еще module, dynamic и operator lookup - тут кстати импорт отдельных деклараций так же помогает);<br /><br />Продолжение во второй части + все ссылки.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2026-01-19T15:07:42+00:00"}, {"id": "https://t.me/c/2068344133/342", "url": "https://t.me/c/2068344133/342", "title": "#aoc25 #swift #fp  Advent of Code 2025   В прошлом году, в декабре у нас (ладно, у небольшой группы ", "content_html": "#aoc25 #swift #fp<br /><br /><strong>Advent of Code 2025 <br /></strong><br />В прошлом году, в декабре у нас (ладно, у небольшой группы людей) был no returner <a href=\"https://t.me/contravariance/213\">FP style челендж литкод дейликов</a>. В этом же году снова вернулись к традиционному AOC, жаль что всего 12 дней. Абсурдный no returner не делаем больше (хотя, по старой памяти иногда проскакивает), но теперь репертуар инструментов <em>слегка</em> изменился: все тот же FP style, но уже добавились (на видео не попали) optics, SIMD, inline collections, еще больше bit hacking tricks и GPU kernels - в AOC то никаких лимитов!<br /><br /><blockquote>Кстати, там в <em>этих</em> <em>твитторах</em> Джейкоб Бартлетт (известный в СНГ телеграммах по статьям, о том какой Swift сложный ряяяя) начал решать литкод и ему попалось одно из моих абсурдных решений. К его сожалению не самое абсурдное :D. Одно из из них <a href=\"https://t.me/contravariance/329\">подробно разобрано в посте выше</a>. <br /></blockquote><br /><br />Все решения AOC публиковать не буду, вчера и сегодня прям классные задачи, но у них есть нечто общее - они все решены максимально лаконично. Ну и насколько же Swift офигенный! <br /><br /><blockquote>Знаете еще что примечательно, не сразу осознал (я опять про type system) - ведь bottom type с Swift 6.0 и non-copyable generics изменился. Показалось не самым очевидным, когда фундаментальное знание, о системе типов органично меняется за столько лет. <br /></blockquote><br /><br />Суть ежегоднего адвента <em>развитие</em> и <em>любовь</em> к программированию! А отсуствие глобальноо рейтинга только на руку с учетом вайбкодерства, заруинившее acceptance рейтинг литкод задач. <br /><br />Эвристически я понимаю, что AOC из вас решают очень не многие (4½ человека), но всем кто пробует и практикует (да и вообще всем, будет здорово если кто попробует впервые) - лучи добра и предновогоднего настроения друзья! <br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-12-08T16:37:00+00:00"}, {"id": "https://t.me/c/2068344133/341", "url": "https://t.me/c/2068344133/341", "title": "SE-0479 кстати отложили опять в долгий ящик (lack of partial application, perf. issues, type system ", "content_html": "SE-0479 кстати отложили опять в долгий ящик (lack of partial application, perf. issues, type system soundness etc.), много причин компиляторных, которые имо хорошо хайлайтят, что сабскрипты и остальные функт типы на компиляторном уровне <em>довольно сильно</em> отличаются (примечательно, что фактически их минимум штук 8);<br /><br />Хотя, вроде семантика функ типа, что - там, что - тут; На деле, между сабскриптом и методом даже диспатч будет отличаться, для сабскриптов многие эффекты не доступны, а в конечном итоге сабскрипт это compiler-generated параметризированный проперти аксессор. У них с методом даже full mangled symbol name по разном правилам синтезируются, разные правила работы overload’a, специалзации дженериков - а один аксессор в witness table (get / set) занимает сразу 3 accessor слота (read/write/RMW), а ну еще они yield’ят/резюмят контрол флоу (ряя корутина, крикнет кто нибудь и будет не совсем прав) - а метода / функции занимают - 1 слот; Детали ABI и инлайнинга тоже отличаются;<br /><br />Примечательно, что non-hashable параметр/аргумент не передать в такой KeyPath - одно из фундаментальных ограничений; По сути, через обертку функ-типа по стабильному Hashable ключу происходит доступ к значению, что максимально быстро/просто сравнить через referential/value identity при диффе, а более конвиненциальный non-nominal / structural тип (метод) - или <em>еще хуже</em> - closure уже не сравнить <em>так просто</em>;", "date_published": "2025-12-02T17:35:53+00:00"}, {"id": "https://t.me/c/2068344133/340", "url": "https://t.me/c/2068344133/340", "title": "SwiftUI Bindings  Сейчас немного загружен задачами, поэтому обещанный пост про детали работы @result", "content_html": "<strong>SwiftUI Bindings</strong><br /><br />Сейчас немного загружен задачами, поэтому обещанный пост про детали работы <code>@resultBuilder</code> будет на следующей неделе.<br /><br />А пока хочется поговорить про работу с <code>Binding</code> в SwiftUI. Думаю, многие читали статью Chris Eidhof <a href=\"https://chris.eidhof.nl/post/binding-with-get-set/\">Not all Bindings are created equal</a>.<br /><br />В ней автор рассказывает о том, что <code>Binding(get:set:)</code> — достаточно опасная вещь, потому что вызывает постоянные инвалидации <code>View.body</code>.<br /><br /><pre><br />    <code class='language-swift'><br />        <br />struct ContentView: View {<br />  @State var value1 = false<br />  @State var value2 = false<br />  <br />  var body: some View {<br />    VStack {<br />      Toggle(&quot;Test&quot;, isOn: $value1)<br />      Nested(value2: $value2)<br />    }<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br />В этом примере, если мы изменяем <code>value1</code>, то тело <code>Nested</code> не вычисляется заново, потому что в ней ничего не изменилось. Более того, при изменении <code>value2</code> будет пересчитываться только тело <code>Nested</code>, потому что <code>ContentView</code> не использует это значение.<br /><br />Но если использовать <code>Binding(get:set:)</code>:<br /><pre><br />    <code class='language-swift'><br />        <br />// ...<br />VStack {<br />  Toggle(&quot;Test&quot;, isOn: $value1)<br />  Nested(<br />    value2: Binding(<br />      get: { value2 },<br />      set: { value2 = $0 }))<br />}<br />{}<br />    </code><br /></pre><br /><br />Теперь при изменении любого значения — <code>value1</code> или <code>value2</code> — всегда пересчитываются тело и <code>ContentView</code>, и <code>Nested</code>.<br /><br />Это происходит из-за замыканий, которые SwiftUI не умеет сравнивать. В отличие от <code>$value2</code>, который сохраняет ссылку на <code>@State</code>.<br /><br />Понятно, что в таком простом кейсе вряд ли кто-то станет использовать <code>Binding(get:set:)</code>. <br /><br />Но что, если нам нужно сконвертировать какой-то тип?<br /><pre><br />    <code class='language-swift'><br />        <br />struct ContentView: View {<br />  @State var value: Set&lt;PresentationDetent&gt; = [.medium, .large]<br />  <br />  var body: some View {    <br />    VStack {<br />      Nested(<br />        text: &quot;Enable Medium Detent&quot;,<br />        value: Binding(<br />          get: { value.contains(.medium) },<br />          set: { isMediumDetentEnabled in<br />            if isMediumDetentEnabled {<br />              value.insert(.medium)<br />            } else {<br />              value.remove(.medium)<br />            }<br />          }))<br />      <br />      Nested(<br />        text: &quot;Enable Large Detent&quot;,<br />        value: Binding(<br />          get: { value.contains(.large) },<br />          set: { isLargeDetentEnabled in<br />            if isLargeDetentEnabled {<br />              value.insert(.large)<br />            } else {<br />              value.remove(.large)<br />            }<br />          }))<br />    }<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br />В этом примере уже сложно придумать, что-то хорошее. Как мы знаем из <a href=\"https://t.me/contravariance/293\">[SE-0479] Method and Initializer Key Paths</a>, Swift пока что не умеет конвертировать функции в <code>keyPath</code>. Но я был удивлён, когда узнал, что он умеет это делать для <code>subscript</code>:<br /><pre><br />    <code class='language-swift'><br />        <br />private extension Set&lt;PresentationDetent&gt; {<br />  subscript(contains element: Element) -&gt; Bool {<br />    get { contains(element) }<br />    set {<br />      if newValue {<br />        insert(element)<br />      } else {<br />        remove(element)<br />      }<br />    }<br />  }<br />}<br /><br />// ...<br />var body: some View {    <br />  VStack {<br />    Nested(<br />      text: &quot;Enable Medium Detent&quot;,<br />      value: $value[contains: .medium])<br />  <br />    Nested(<br />      text: &quot;Enable Large Detent&quot;,<br />      value: $value[contains: .large])<br />  }<br />}<br />{}<br />    </code><br /></pre><br /><br />И помимо того, что такой код попросту намного компактнее и читабельнее, он ещё и работает так же эффективно, как и первое решение, пересчитывая только те <code>View.body</code>, которые изменились🫨", "date_published": "2025-12-02T17:35:42+00:00"}, {"id": "https://t.me/c/2068344133/338", "url": "https://t.me/c/2068344133/338", "title": "#applesilicon #compiler #swift #lowlevel  Demystifying Instruction Delivery Optimizations: Apple Sil", "content_html": "#applesilicon #compiler #swift #lowlevel<br /><br /><strong>Demystifying Instruction Delivery Optimizations: Apple Silicon Core Pipeline Vol. II<br /></strong><br />У P ядер есть out-of-order speculative execution. Промах по кешу инструкций составляет от 10-40 циклов (в среднем для M1). А dynamic dispatch существенно увеличивает шанс промаха, где virtual table lookups и witness table dispatch создают indirection слой и те самые speculative execution pipelines просто флашаются (flushing)! Speculative executor часто благодаря эвристикам предотвращает те самые data/instruction cache misses. Но когда этого не происходит то:<br /><br />• Импакт для VTable кеш миссес 2-4 cycles или от 2-4x медленнее, чем прямой вызов<br />• Для WTable от 10-20 cycles - 5-15x медленее, чем прямой вызов<br />• Для Message Dispatch 100-200 cycles или 10-100x медленее, чем прямой вызов<br /><br /><blockquote>Мы платим относительно много за месседжсенд, но при этом даже если что то посвизленно то посвизленно один раз при запуске апки; Никто не страдает тем что динамически в рантайме добавляет удаляет методы; Спасибо @wach_mann за фидбек <br /></blockquote><br /><br />А прямое обращение в DRAM - 280-350 cycles или 95 ns на M1 чипе! Если заскейлить - обращение к DRAM эквивалентно полету до Юпитера и обратно, а в L1 все равно что взять предмет со стола! Мы просто этого не замечаем! (Стоит сделать дикслеймер, что количество циклов может варьироваться и на то много причин, смотрите страницу 277 в гайде (cache &amp; memory access latency для М1 чипа));<br /><br />Инлайнинг часто спасает в таких ситуациях (when applicable), но знали ли вы про аутлайнинг? Outlining намного ближе, чем мы представляем: например литеральный массив декларированный в функции, становится глобалом, аутлайниться и размещается в .rodata сегменте; На самом деле не только литеральные массивы, там много примечательного (смотрите <code>ObjectOutliner</code> оптимизацию, ссылка снизу).<br /><br />Аултайнинг встречается довольно часто, когда вы размещаете reference type в value type и даже можно было получить так называемый outlined object destruction краш в более раннем Swift (редкий и нетривиальный для фикса); <br /><br />Если инлайнинг увеличивает бинарник, то аутлайнинг напротив его уменьшает, так как например hot execution paths в функциях выносятся в микро-функции, а спекулятивный executor может существенно ускорить выполнение такого метода! Не все execution paths в ваших функциях одинаковые и при должном low-level дизайне можно повлиять на L1 Instruction (L1I) TLB!<br /><br />Так же в гайде есть про: loop unrolling, hot path straightlining и мой любимый branchless execution аля вывернем наизнанку выражение самым неподдерживаемым способом :D; Вы могли <a href=\"https://t.me/contravariance/329\">читать в прошлых постах про некоторые техники branchless execution</a>; (бранчинг для CPU не самая приятная операция, чуть подробнее тоже в гайде - да и у Тененбаума хорошо написано);<br /><br />Примечательно, что про Return Address Stack и тут упомянуто про рекурсию: restructure algorithms to avoid deep call stacks;<br /><br />Есть и более “земная” материя: про инструменты Xcode например. <br /><br /><blockquote>В начале я написал про гетерогенность комьют платформы, но чтобы вникнуть в ее тонкости, надо глубоко понимать, что стоит за инструкциями, которые мы пишем. Если вам интересно, ставьте реакции и я покажу, как написать FPшные версии zip, map и reduce на Metal compute kernel и мы даже порешаем LeetCode на GPU! <br /></blockquote><br /><br />• <a href=\"https://developer.apple.com/download/apple-silicon-cpu-optimization-guide/\">Apple Silicon CPU Optimization Guide Version 4</a> (292 pages long) (рекомендую страницы: 166, 170, 171, 183, 185, 198, 200 и в целом 5 главу целиком)<br />• <a href=\"https://github.com/swiftlang/swift/blob/09c828cbcbf1743c75a8c15067836f35ff7dc80a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift\">SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ObjectOutliner.swift</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-11-14T08:08:48+00:00"}, {"id": "https://t.me/c/2068344133/337", "url": "https://t.me/c/2068344133/337", "title": "#applesilicon #compiler #swift #lowlevel  Demystifying Instruction Delivery Optimizations: Apple Sil", "content_html": "#applesilicon #compiler #swift #lowlevel<br /><br /><strong>Demystifying Instruction Delivery Optimizations: Apple Silicon Core Pipeline Vol. I<br /></strong><br />Apple уже давно дает нам гетерогенную комьют платформу (CPU, GPU, NPU, media / imaging accelerators etc), вот только утилизируют ее в какой то степени - немногие, а по настоящему шарят - единицы. Гетерогенная компьют платформа это комплекс гетерогенных программируемых вычислительных блоков + плюс унифицированная модель работы с памятью и общий софтверный стек. Рычагами выступают Swift и амбрела в виде Metal API (MSL, MPS, compute graph, BSN) вместе с Accelerate. В рабит хол “а какие ето задачи надо решать шобы эта все юзать?”, “ми можим через LLM все нагенерить!” я лезть не буду - оставляю это софистам и демагогам;<br /><br /><blockquote>Чтобы вам было комфортно понимать, что написано дальше даю небольшой дикслеймер: нужно базово знать computer architecture, operating systems и наверно компиляторы еще; <br /></blockquote><br /><br />Apple уже достаточно давно публикует довольно нишевый технический гайд по Apple Silicon (ссылка снизу во втором посте). Если вы задавались вопросами: какой точный размер кеш линии, L1 instruction cache specifics, на каких ядрах работает out-of-order speculative execution, микраархитектурные характеристики, да в конце концов какой лейтенси доступа к кешам, в каких случаях инструкция распадается на micro operation (μops), почему лучше избегать deep call stacks (на то несколько причин, одна из них это ARC лишь эвристически поддерживает tail call recursion) - то вам будет интересно;<br /><br />What the frog is μops? Это микрооперации - базовые элементарные действия, выполняемые вычислительными блоками на самом низком уровне. Ассемблерные инструкции вроде ADD или MOV на деле раскладываются компилятором и декодером процессора на последовательность этих самых μops.<br /><br />Apple Silicon умеет распараллеливать μops во множестве сценариев: вы, вероятно, слышали о векторизации, но это лишь один из способов преобразовать seemingly линейными операции в параллельные на уровне микроархитектуры. На самом деле то, что вы воспринимаете как последовательное выполнение инструкций, часто внутри ядра распараллеливается на μops, но только когда только возможно (это не MIMD по Флину).<br /><br />Например, одна 32b инструкция после декодирования может разложиться на несколько μops:<br /><br />• μops читают разные source-регистры<br />• μops записывают в разные destination-регистры<br />• μops уходят в разные execution pipelines(ALU, AGU, MUL, LSU, FP etc);<br /><br />Все это делается на микроархитектурном уровне для улучшения вычислительной плотности (computational density); Чтобы не сложить неверное впечатление, другие микраархитектуы это тоже делают, но совершенно в разных пропорциях и формах;<br /><br />Integer add (op-add) инструкция разбивается на два μops для увеличения пропускной способности: обычно ADD инструкция декодируется на один μops и передается integer ALU. А теперь, начиная M4/A18 P-cores (P - performance, E - efficiency) одна такая ADD инструкция разбиватется на две внутренние μops, где:<br /><br />• μop 1 это partial addition / operand prep<br />• μop 2 это результирующая аккумуляция через multiply-pipeline datapath<br /><br />Они на микроархитектурном уровне распараллеливаются на разные пайплайны! Apple начала меняет части архитектуры с M4/A18, где P ядра получает огромное количество тех самых multiply units для ML/graphics workloads, при этом уменьшая количество выделенных ALUs (связано с переиспользованием pipeline’ов для FMA и INT ops); <br /><br /><blockquote>Новый чип или изменение микроархитектуры это потенциально сильно интереснее увеличенного количества ядер или их частоты, вся красота - в микроархитектуре и имплементационных деталях. Ядра зачастую лишь маркетинг! Имо весьма очевидный абзац, но в контексте конкретных примеров приобретает слегка другой вес; Учитывайте это когда обновляете железо.<br /></blockquote><br /><br />И это лишь маленький пример! Продолжение во второй части.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-11-14T08:07:45+00:00"}, {"id": "https://t.me/c/2068344133/335", "url": "https://t.me/c/2068344133/335", "title": "#swift #typesystem #compiler   Type Checker: Constraint Sovler &amp; Overload Ranking  TL;DR Я накат", "content_html": "#swift #typesystem #compiler <br /><br /><strong>Type Checker: Constraint Sovler &amp; Overload Ranking</strong><br /><br />TL;DR Я <a href=\"https://forums.swift.org/t/roadmap-for-improving-the-type-checker/82952\">накатываю небольшой фидбек на constraint solver / ranking алгоритм к роудмапу Славы Пестова</a>, следом пишу буквально 3 строчки тривиального FP style кода:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />Dictionary(divisibles.map{ ($0, 1) }, uniquingKeysWith: +).lazy<br />  .filter { $0.value % k == 0 }<br />  .map(*)<br />  .reduce(0, +)<br />{}<br />    </code><br /></pre><br /><br />Получаю <em>любимый</em>: <br /><br /><pre><br />    <code class='language-'><br />        <br />The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions<br />{}<br />    </code><br /></pre><br /><br /><em>Двумя минутами ранее</em> пишу не менее тривиальные пайплайны:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />...<br />bytes.sorted().adjPair.lazy<br />  .map { ($0.1 - $0.0, $0) }<br />  .filter { $0.0 != 1 }<br />  .map { Array($0.1.0+1..&lt;$0.1.1) }<br />  .flatMap(\\.self)<br />{}<br />    </code><br /></pre><br /><br />И еще <em>ровно</em> 7ю минутами ранее:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />...<br />directions.forEach { dx, dy in<br />  sequence(state: (r: row + dx, c: col + dy)) { state in<br />    guard 0..&lt;m ~= state.r &amp;&amp; 0..&lt;n ~= state.c else { return nil }<br />    defer { state = (state.r + dx, state.c + dy) }<br />    return state<br />  }<br />  .prefix(while: { (r, c) in map[r][c] != WALL &amp;&amp; map[r][c] != GUARD })<br />  .forEach { (r, c) in map[r][c] = GUARDED }<br />{}<br />    </code><br /></pre><br /><br />Шутки-шутками, но на то есть причины: двунаправленный (bidirectional) Hindley-Milner <em>сильно</em> нюансный, это инженерно решаемая задача - с условностями и допущениями, математически, через type theory - все сильно сложнее. <br /><br /><blockquote>Строгое математическое обоснование двунаправленного вывода (с subtyping, overloading, type classes, effects и т.д.) - это чрезвычайно сложная область, далeкая от чистого HM</blockquote><br /><br />Перепрыгивая на смежную, но не менее примечательную тему: все оверлоады (кроме эвристик, которые из них на прикрепленном медиа) проходят через overload resolution, где работает обобщенный принцип: &quot;most specific overload should win&quot;. Вы с этим сталкивались либо явно и осознанно, либо не явно и не осознанно. <br /><br />Overload resolution это один из этапов type cheker&#x27;a, схематично:<br /><br /><strong>Expression Parsing &amp; AST Construction</strong> <strong>→</strong> <strong>Type Variable Introduction → Constraint Generation</strong> <strong>→</strong> <strong>Constraint Solving →</strong> <strong>Overload Resolution</strong> <strong>→</strong> <strong>Solution Ranking</strong><br /><br /><blockquote>Пайплайн сильно сложнее, схематично это гигантский механизм, а диагностики получаемые даже из тривиального кода - листинги кода. Можете сами посмотреть, через флаг <br />-debug-constraints</blockquote><br /><br />Так называемый ранкинг или <em>tentative</em> ranking подхода - назначает ранг оверлоаду, до тех пор пока один из кандидатов не выигрывает, либо компилятор выдаст диагностику. Но не все оверлоады легко разрешимы. Есть много неочевидностей и неконсистнтностей в этом механизме и констрейнт солвере. Я немного это отразил в сообщении в треде Славы по тайпчекеру (если интересно почитать, там на англ все);<br /><br />Если захотите поиграться, то вот вам игрушка: в комментах я максимально лаконично описал суть ошибок:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />protocol P {<br />  init()<br />}<br />extension Int: P { }<br /><br />struct S&lt;T: P&gt; {<br />  init(_ x: T = .init()) { }<br />  init(_ x: T? = nil) { }<br /><br />  func f(_ x: T = .init()) { }<br />  func f(_ x: T? = nil) { }<br /><br />  static func testInit() {<br />    _ = S&lt;T&gt;()        // `.init()` version has higher rank<br />    _ = S&lt;T&gt;.init()   // Ambiguous use of &#x27;init(_:)&#x27;<br />    S&lt;T&gt;().f()        // Ambiguous use of &#x27;f&#x27;<br />    _ = S&lt;T&gt;.init     // Ambiguous: cannot take unapplied constructor reference<br />    _ = S&lt;T&gt;.f        // Ambiguous: cannot take unapplied function reference<br />  }<br />}<br /><br />S&lt;Int&gt;.testInit()<br />{}<br />    </code><br /></pre><br /><br />Коротко: тут работает эвристика - специальные правила на constraint solver для default constructor parameter ranking - где .init() всегда выигрывает у nil литерала, но это правило униморфно и симметрично уже <strong>не работает</strong> для функциональных типов и unapplied function reference и даже constructor reference. <br /><br /><blockquote>Если хотите прям мега развернутый материал, который даже Слава Пестов еще не написал, то я сделаю публичным весь пайплайн type checker&#x27;a до самых мелких деталей, со всеми ссылками, так что вы сможете &quot;<em>задушить</em>&quot; любого на воображаемом собесе (лол). Ставьте <em>голову</em> или что нравится, или не ставьте - я не тороплюсь открывать скрытое;</blockquote><br /><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.2.1/lib/Sema/CSRanking.cpp\">lib/Sema/CSRanking.cpp</a><br />• <a href=\"https://github.com/swiftlang/swift/blob/release/6.2.1/lib/Sema/CSSolver.cpp\">lib/Sema/CSSolver.cpp</a><br />• <a href=\"https://forums.swift.org/t/roadmap-for-improving-the-type-checker/82952\">Roadmap for improving the type checker</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-11-02T17:32:28+00:00"}, {"id": "https://t.me/c/2068344133/334", "url": "https://t.me/c/2068344133/334", "title": "#swift #mach #runloop #libdispatch   Demystifying CFRunLoop.c. Part II.  kernel-level APIs для мульт", "content_html": "#swift #mach #runloop #libdispatch <br /><br /><strong>Demystifying CFRunLoop.c. Part II.</strong><br /><br />kernel-level APIs для мультиплексирования событий ввода/вывода - другими словами, это способ ждать сразу множество файловых дескрипторов, сокетов, таймеров и других источников событий в одном системном вызове*<br /><br />kqueue (BSD-системы e.g. macOS, iOS, FreeBSD …) &lt;sys/event.h&gt;<br />epoll (Linux) &lt;sys/epoll.h&gt; - можно думать, как об аналоге kqueue, но с немного другой моделью; <br /><br />*на POSIX’e poll<br /><br />Примечательно, что решение проблемы C10k началось именно с идей мультиплексирования ввода/вывода - эволюционно, начиная с select() (1980) и далее с современными механизмами (epoll, kqueue, IOCP). На данный момент проблема смасштабированна на C10m; Это не совсем задачи iOS, но они хорошо ложатсья на базу и концептуальное понимание взаимодействия OS ↔ scheduling ↔ throughtput management ↔ concurrency;<br /><br /><strong>Примечательная имба #1</strong><br /><br /><pre><br />    <code class='language-asm'><br />        <br />asm __volatile__ (&quot;&quot;);<br />{}<br />    </code><br /></pre><br /><br /><a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2205\">чтобы запретить tail-call optimization</a>. Это важно для символов вроде <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2181\">__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__</a>, чтобы стектрейсы в crash логах оставались читаемыми<br /><br /><strong>Примечательная</strong> <strong>имба #2 (с монолога </strong><a href=\"https://en.wikipedia.org/wiki/To_be,_or_not_to_be\"><strong>Гамлета, Шекспир</strong></a><strong>)</strong><br /><strong><br />• </strong>/* In that sleep of death what nightmares may come ... */ - <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2716\">вставлена прямо в теле функции __CFRunLoopServiceMachPort(...) перед бесконечным циклом</a><br />• Формулировка контекста (mach_msg - сон, события - nightmares) - удачная метафора и технически отражает суть<br />• “Cон смерти” - это mach_msg() блокировка потока, а nightmares - все события, что разбудят его (таймеры, сокеты, UI, sources 1го уровня)<br /><br /><pre><br />    <code class='language-c'><br />        <br />…<br />static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header_t **buffer, size_t buffer_size, mach_port_t *livePort, mach_msg_timeout_t timeout, voucher_mach_msg_state_t * _Nonnull voucherState, voucher_t *voucherCopy, CFRunLoopRef rl, CFRunLoopModeRef rlm) {<br />    Boolean originalBuffer = true;<br />    kern_return_t ret = KERN_SUCCESS;<br />    for (;;) {  /* In that sleep of death what nightmares may come ... */<br />        mach_msg_header_t *msg = (mach_msg_header_t *)*buffer;<br />…<br />{}<br />    </code><br /></pre><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-10-07T13:55:48+00:00"}, {"id": "https://t.me/c/2068344133/333", "url": "https://t.me/c/2068344133/333", "title": "#swift #mach #runloop #libdispatch   Demystifying CFRunLoop.c. Part I.  Disclamers • Хоть пост и наз", "content_html": "#swift #mach #runloop #libdispatch <br /><br /><strong>Demystifying CFRunLoop.c. Part I.</strong><br /><br /><blockquote><strong>Disclamers</strong><br />• Хоть пост и называется demystifying, за кадром остается существенная часть имплементационных деталей. Это заметка-пост, а не попытка обьяснить все тонкости ground-up для столь примечательного механизма;<br />• 21 референс прикреплен к вашему вниманию. В некоторых proposals / whitepapers меньше; </blockquote><br /><br /><strong>Примечательно, но не очень (под кофе пойдет):<br /></strong><br />На архитектурном и концептуальном уровне есть некоторая степень приближения между лупером и ранлупом: even loop, reactor-based, user-space-to-kernel-space multiplexing…) - ранлуп (внезапно) это не просто “цикл держащий поток живым”, а messaging-механизм для асинхронного межпоточного взаимодействия и мост между user-space и kernel-space для демультиплексирования событий. <br /><br />• CFRunLoop <a href=\"https://github.com/opensource-apple/CF/blob/master/CFRunLoop.c\">≈2015 год 3909 NLOC</a> (<a href=\"https://developer.android.com/reference/android/os/Looper\">Looper.java</a> всего <a href=\"https://android.googlesource.com/platform/frameworks/base/+log/refs/heads/main/core/java/android/os/Looper.java\">309 NLOC</a>)<br />• ≈2025 вырос до 4772 NLOC (<a href=\"https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/Looper.java\">Looper.java вырос раза в ≈2-2.5</a> (still under 1k))<br />• в CFRunLoop есть явные хуки вроде CFRunLoopWakeUp() и сложная логика wakeup-reason; в Android wakeup/dispatch происходит через enqueuing/Looper.loop()<br />• Apple активно интегрирует CFRunLoop с libdispatch (dispatch sources, порты), а Android связывает Looper с платформенным message pump и framework event producers<br />• … обратно к нашим <em>баранам</em>, мы же батл лупера с ранлупом не устраиваем (???)<br /><br /><strong>Примечательно, но модель приближения - обобщенная:<br /></strong><br />• Swift RunLoop (…<a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/ec675206c8cd939fbd4783421ea07954dcb5e175/Sources/Foundation/RunLoop.swift#L55\">/Foundation/RunLoop.swift</a>) - это тонкая оболочка над CFRunLoopRef<br />    • Все механизмы таймеров (<a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L1397\">CFRunLoopTimer</a>), источников (<a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L1289\">CFRunLoopSource</a>), обсерверов (<a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L1329\">CFRunLoopObserver</a>) и wake-ups напрямую делегируют вызовы в C код из этого файла<br />• За ~20 лет почти не изменился интерфейс CFRunLoop* API<br />    • Основная эволюция - интеграция с GCD, XPC, и modern Swift concurrency (RunLoop.main.perform → Task bridge)<br /><br /><strong>Следующее приближение примечательности:<br /></strong><br />• CFRunLoop - мост между CoreFoundation и Mach: использует mach_msg для получения событий с ядра; фактически реализует event loop уровня ОС поверх Mach портов; интегрирован с GCD (libdispatch)<br />• Для <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L3039\">Darwin/Mac-сборок CFRunLoop обслуживает Mach-порты</a> и блокируется на mach_msg в ожидании сообщений; это ключевой момент архитектуры. Интеграция с libdispatch имеет <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2971\">специальные dispatch port wakeups</a><br />• Sources:<br />    • Source 0 - внутрипроцессное взаимодействие, требует ручного CFRunLoopWakeUp()<br />    • Source 1 - системные события, завязанные на Mach порт<br />    • Оба используют общий API <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L4126\">CFRunLoopSourceCreate</a>(…), но семантика разная - это видно в <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2208\">__CFRunLoopDoSource0</a>/1() функций<br />• Есть хуки <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L193\">CFRUNLOOP_SLEEP</a>(), <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L203\">CFRUNLOOP_WAKEUP</a>() для Instruments<br />    • Используются в <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2713\">__CFRunLoopServiceMachPort</a> и <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L2935\">__CFRunLoopRun</a> для измерения блокировок<br />• Apple исторически держит один код для macOS/iOS/watchOS, с ветвлением по макросам<br />    • Версия из Swift-corelibs работает и на Linux, где Mach заменён на <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L479\">kqueue</a> / <a href=\"https://github.com/swiftlang/swift-corelibs-foundation/blob/main/Sources/CoreFoundation/CFRunLoop.c#L418\">epoll</a> (тут две разные ссылки прикреплены)<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-10-07T13:55:42+00:00"}, {"id": "https://t.me/c/2068344133/332", "url": "https://t.me/c/2068344133/332", "title": "", "content_html": "", "date_published": "2025-09-14T05:37:30+00:00"}, {"id": "https://t.me/c/2068344133/330", "url": "https://t.me/c/2068344133/330", "title": "#swift #os #darwin #mach #kernel #swiftconcurrency #libdispatch #pthreads  Demystifying Swift Concur", "content_html": "#swift #os #darwin #mach #kernel #swiftconcurrency #libdispatch #pthreads<br /><br /><strong>Demystifying Swift Concurrency. Cooperative Thread Pool Vol I. : Kernel Round-Trip.</strong><br /><br />This is one of the most ridiculously in-depth technical notes that I’ve posted ever. The subject is so dense with detail that I had to omit large portions just to compose a high-level yet still detailed map of the full round-trip stack: how a Swift concurrency task (internally a (<code>Job</code>) <code>SwiftJob</code>) ends up being executed all the way down at the <code>Mach scheduler</code>, underlying <code>pthread_t</code> initialization flow and the whole thread’s lifecycle both in <code>Darwin</code> up to the <code>Mach kernel</code>!<br /><br /><blockquote><strong>Disclaimers<br /></strong>• 1) The <code>libdispatch</code> maintainers do not do most of their work in open source.<br />• 2) Many known implementation details of libdispatch may already be outdated before of the {1}.<br />• 3) This summary reflects what is publicly available at the time of writing and affected by {1,2}.<br />• 4) I may never publicly release Vol. II or Vol. III. The naming of this post reflects only that much more could still be written.</blockquote><br /><br />The so-called cooperative thread pool is not fully cooperative in practice. It is, more accurately, non-preemptive but cooperative when possible. It strives to behave cooperatively and often does so quite effectively. However, as <a href=\"https://t.me/contravariance/324\">I explained in the previous post, it can still overcommit</a>.<br /><br />The nature of overcommitment in this pool is different from how GCD itself overcommits. GCD has hidden overcommit QoS classes, and in some sense, is designed to allow more threads than there are CPU cores, especially under high load, to prevent deadlocks and avoid stalling high-priority work. There are also other mechanisms by which GCD overcommits, including its global concurrent queue dynamically creating extra pthreads when the pool of worker threads is exhausted, which can temporarily exceed the number of logical cores available.<br /><br />The pool itself is implemented in libdispatch and Swift’s integration with the pool is mostly just calling a function to submit jobs. Several stages are happening before a <code>Job</code> (<code>SwiftJob</code>) is passed to the function, but these stages are more about <code>SIL</code> to <code>IRGen</code> functional splitting / coroutine lowering that <a href=\"https://t.me/contravariance/290\">I also deeply explored in the previous post</a>. <br /><br />Before submitting a Job, executor gets a handle to an appropriate <code>dispatch_queue_t</code> with a priority. Memory load order is determined, depending of the swift’s concurrency back deployment flag, as well as either create a cooperative queue (if available) or fallback to standard global queue. After that a Job’s pointer is casted and passed to the <code>dispatch_queue_t</code>. <br /><br /><code>dispatch_queue_t</code> has opaque implementation, details are hidden but what we know for sure is that it operates on top of <code>pthread_t</code>, by scheduling work items onto a shared pool of threads created with <code>pthread_create</code> internally by <code>libdispatch</code>. Multiple <code>dispatch_queue_t</code>`s feed into the same pool of <code>pthread_t</code>`s - hte pool decides which thread picks up a given block, except for the special case: <strong>the main queue is bound to the main thread</strong>’s <code>pthread_t</code>. <br /><br />Darwin&#x27;s implementation of the <code>pthread_t</code> can be found in thread&#x27;s <code>internal/pthread.h</code>, and has remained fairly stable over the years. The library initializer, thread <code>__pthread_init( )</code> , is responsible for creating the default <code>pthread_t</code>, which serves as the template for all threads, as well as the default <code>pthread_attr_t</code>, which is the default set of thread attributes. Attribute list has a number of entries, such as: stack size, scheduling priority and quantum, flags (detached, inherit), policy, fast path (whether kernel allocates thread and stack or not (default is true), QoS class, cancel state (<code>HREAD_CANCEL_ENABLE</code> | <code>PTHREAD_CANCEL_DEFERRED</code>) etc. <br /><br />Continued in the comments below.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-09-07T13:00:03+00:00"}, {"id": "https://t.me/c/2068344133/329", "url": "https://t.me/c/2068344133/329", "title": "#swift #dsa #leetcode #bithacks  Disclaimers:  • Friends, there was a dilemma: use a “Toxic” or “…Ba", "content_html": "#swift #dsa #leetcode #bithacks<br /><br /><blockquote>Disclaimers: <br />• Friends, there was a dilemma: use a “Toxic” or “…Baby One More Time” cover from Britney Spears for the post’s story; the choice was absurdly hard, so the pick ended up being “Figure It Out” by Royal Blood - couldn’t resist rock. <br />• The bit hacks shown here are purely for fun and joy; feel free to ignore them if the only priority is shipping exactly what a manager requires :]. </blockquote><br /><br /><strong>Bit Hacks: Branchless Binary Lookup Tables</strong><br /><br />Everything (more often than not) in computing and systems design is a trade‑off; bit hacks are one such trade‑off.  Personally, the goal is to develop patterns that let one branch quickly to promising solution spaces when tackling computational or design problems. These patterns often extend beyond the traditional “design pattern” taxonomy. <br /><br />Human brains are excellent at pattern recognition, so it’s worth leveraging that built‑in capability and re‑introducing such patterns where helpful. Bit manipulation can look like dark magic, but at its core it is simply the application of per‑bit logical operations governed by Boolean algebra (e.g., NOT/AND/OR/XOR mapped to ~, &amp;, |, ^), which is the same algebra used in digital logic and taught in standard CS curricula;<br /><br />I took today’s LeetCode daily easy (<a href=\"https://leetcode.com/problems/find-closest-person/\">3516. Find Closest Person</a>) and solved it in five different ways. That’s a habit: relying on a single, well‑known pattern rarely creates the kind of recall‑friendly, positive reinforcement loop that makes ideas stick. <br /><br /><blockquote>Briefly, complex concepts consolidate best when practice is spaced over time and varied in form - mixing retrieval, re‑expression, and constraint changes - so solving the same problem via multiple approaches strengthens long‑term memory and transfer. <br /></blockquote><br /><br />We’ll start with the most straightforward solution and finish with a fully branchless variant, including a ground up reimplementation of a few compiler‑level idioms and a bit‑packed lookup‑table model (ridiculous)! <br /><br />Naive solution is quite straightforward:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />func findClosest(_ x: Int, _ y: Int, _ z: Int) -&gt; Int {<br />  let (a, b) = (abs(z - x), abs(z - y))<br />  return a &gt; b ? 2 : a &lt; b ? 1 : 0<br />}<br />{}<br />    </code><br /></pre><br /><br />But what if an interviewer decided to make it infinitely more complex and asked:<br />• Reimplement the abs function without branching. Wait, what??<br />• Don’t use branching at all.<br /><br />Hmm, okay then—let’s begin with a reimplementation of abs. But before doing that let’s dig into the compiler and see how <a href=\"https://github.com/swiftlang/swift/blob/main/stdlib/public/core/Integers.swift#L346\">abs is implemented</a>:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />…<br />@inlinable<br />public func abs&lt;T: SignedNumeric &amp; Comparable&gt;(_ x: T) -&gt; T {<br />  if T.self == T.Magnitude.self {<br />    return unsafe unsafeBitCast(x.magnitude, to: T.self)<br />  }<br />  return x &lt; (0 as T) ? -x : x<br />}<br />…<br />{}<br />    </code><br /></pre><br /><br />A couple of noteworthy points (and yes, I still need a better word than примечательно!):<br /><br />• if T.self == T.Magnitude.self - detects types whose magnitude has the same concrete type as the value itself, which holds for the standard floating‑point types where absolute value does not change the underlying type.<br />• For signed integer types (e.g., Int, Int64, Int128), Magnitude is an unsigned counterpart, so T.self == T.Magnitude.self is false and the function falls back to return x &lt; (0 as T) ? -x : x<br /><br />Quite straightforward, however due to the crazy interviewer we can’t use branching here!<br /><br /><pre><br />    <code class='language-swift'><br />        <br />@_transparent<br />func _abs&lt;T: FixedWidthInteger&gt;(_ x: T) -&gt; T {<br />  let mask = x &gt;&gt; (T.bitWidth - 1)<br />  return (x ^ mask) &amp;- mask<br />}<br />{}<br />    </code><br /></pre><br /><br />Noteworthy points:<br />• @_transparent is an extremely strong form of @inlinable that ensures the call’s stack frame isn’t even preserved in the debug info! Don’t use it!<br />• (x ^ mask) basically is a branchless way to compute absolute value;<br /><br />Continued in the comments below.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-09-04T14:30:05+00:00"}, {"id": "https://t.me/c/2068344133/328", "url": "https://t.me/c/2068344133/328", "title": "#swift #swiftalgorithms #swiftconcurrency   AsyncAlgorithms v1.1  A lot has been happening behind th", "content_html": "#swift #swiftalgorithms #swiftconcurrency <br /><br /><a href=\"https://forums.swift.org/t/kickoff-of-a-new-season-of-development-for-asyncalgorithms-share/81447\"><strong>AsyncAlgorithms v1.1</strong></a><strong><br /></strong><br />A lot has been happening behind the scenes in both the Swift libraries and the compiler over the past few months. Swift Evolution is preparing for the next wave of proposals, while the current batch - under the Swift 6.2 umbrella - is heading toward a major release. <br /><br />Often we need commonly used tools, but expressed in an idiomatic Swift Concurrency style: <em>forward-progress</em> compliant, with concise stream/task-based APIs. Personally, I’ve built a number of private tools to control actor reentrancy in various ways, actor-complaint locks, time and throughtput managmenet and lot more (a topic for future posts). Among them are idiomatic operators like .throttle and .debounce, as well as many other useful async algorithms. <br /><br />One longstanding gap in AsyncStream has been the lack of consistent support for multi-producer sharing. Many attempted solutions suffer from subtle flaws and require careful design. This is precisely the role of the .share() operator. The AsyncAlgorithms team has announced the next iteration of the package, which introduces several major and long-awaited features:<br /><br />• share() operator allows each consumer to make forward progress independently and receive the same values, without replaying from the beginning of time;<br />• MultiProducerSingleConsumerChannel. Basically similar to classic concurrent queues or channels in other languages;<br />• A bunch of new extensions/operator: enumerated(), deferred(), withDeadline, withLatestFrom, mapFailure, <br />• And revisited throttle to refine semantics and reliability.<br /><br />Idiomatic Swift Concurrency sharing is non-trivial: When values from differing isolations cannot be coalesced, two options exist:<br />•  1. <strong>Awaiting</strong>: exerting backpressure across sequences;<br />•  2. <strong>Buffering</strong>: applying backpressure internally to a buffer;<br /><br />Replaying values from the beginning of sequence creation represents a fundamentally different behavior, suited to a separate use case. For .share(), the intended behavior is to share a buffer of values starting from the initialization of each new iteration of the sequence. Control over that buffer should mirror the flexibility of AsyncStream: it may be <em>unbounded</em>, limited to the oldest <em>N</em> elements, or <em>limited</em> to the newest <em>N</em> elements.<br /><br />Another exciting feature under consideration is <em>fusing</em>. You might think “WTF is <em>fusing</em>?”. <em>Fusing</em> <em>optimization</em> refers to combining sequential operations (like filter then map) into a <em>single pass</em>, reducing overhead by eliminating intermediate state or unnecessary tasks. It’s a common optimization in functional, reactive or streaming frameworks. <br /><br />In the context of .share(), <em>fusion</em> is especially relevant: optimizing chained .share() calls can help avoid redundant buffering or performance penalties. Fusing offers a promising direction for performance, though it is still in an early stage of exploration.<br /><br />• <a href=\"https://forums.swift.org/t/kickoff-of-a-new-season-of-development-for-asyncalgorithms-share/81447\">Kickoff of a new season of development for AsyncAlgorithms; Share</a><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-09-04T06:30:01+00:00"}, {"id": "https://t.me/c/2068344133/327", "url": "https://t.me/c/2068344133/327", "title": "#offtopic #swiftconcurrency #swift  Eсли вам ничего не понятно, не переживайте - мне тоже; Каждый де", "content_html": "#offtopic #swiftconcurrency #swift<br /><br />Eсли вам ничего не понятно, не переживайте - мне тоже; Каждый день себя ловлю на этом. В след раз (ровно через n дней) го про forward progress и почему reentrancy &amp; interleaving ключ к cooperative / non-preemptive thread pool model in Swift Concurrency;  Или где cooperative, а где все таки preemptive в Swift Concurrency, а точнее в компиляторе. <br /><br />Как смоделированы расширения на неноминальные функ типы в лице @isolated(any).<br /><br />Куда делись иницилазиторы со @_implicitSelfCapture с Task, но implicit self capture все так же на месте;<br /><br />Как сделать кувырок с reabstraction thunk или async вызов, sync функции с deep-dive в SIL (canonical) -&gt; IRGen; А то мне в панике писали, про боксы для definitive initialization на SIL (raw) стейдже для номинальных value types.<br /><br />Я выговорился немного, спасибо всем ;)<br /><br />People who can’t stand Runglish will be pleased  to know that it’s going to be 100% English-only write-up;<br /><br />@contravariance", "date_published": "2025-09-03T19:40:06+00:00"}, {"id": "https://t.me/c/2068344133/326", "url": "https://t.me/c/2068344133/326", "title": "#swift #typesystem #swiftconcurrency  Demystifying Actor Vol. I: Actor Lock, Active Actor Status, AR", "content_html": "#swift #typesystem #swiftconcurrency<br /><br /><strong>Demystifying Actor Vol. I: Actor Lock, Active Actor Status, ARC Traffic<br /></strong><br />The nominal type actor in Swift is not simply a final class conforming to the <code>Actor</code> protocol (which itself refines <code>AnyObject</code> and <code>Sendable</code> and defines an overridable unowned serial executor). It is also a compact runtime state machine, transitioning between the states scheduled, running, and idle. In other words, an actor is an integral, reentrant, and forward-progress-compliant type-system primitive.<br /><br /><code>ActiveActorStatus</code> is a compact, atomic state machine that encodes an actor’s scheduler state, max enqueued priority, the identity of the thread holding the actor “lock,” and the head of the actor’s job list; on Darwin, the “lock” identity is a libdispatch dispatch_lock_t used for priority escalation, not a traditional mutex guarding a critical section. It’s quite similar to <code>ActiveTaskStatus</code>;<br /><br />All fields are packed into one atomic value (8 or 16 bytes depending on configuration) so state transitions are visible and coherent across threads via single atomic loads/CAS loops as the algorithm converges;<br /><br />Keeping this information co-located in one atomic enables state transitions that are immediately visible to all competing threads, allowing the scheduling algorithm to converge without a separate per-actor mutex in the normal path.<br /><br />On Darwin, the identity of the thread holding the actor is recorded as a dispatch_lock_t (libdispatch) in the DrainLock field; this enables futex-style priority escalation of the running thread if higher-priority work enqueues behind it, resolving priority inversion on the actor. The <code>DrainLock</code>/thread identity is tracked only on platforms that can do 128-bit atomics, keeping the whole status to two machine words; when escalation is disabled or 128-bit atomics are unavailable, the layout omits/marks that slot unused while retaining the single-atomic update model;<br /><br /><blockquote>Mutexes are so simple, they can easily be implemented in user space provided that, if hardware provides atomic read–modify–write (RMW) instructions like TSL (Test-and-Set Lock) or XCHG;</blockquote><br /><br /><pre><br />    <code class='language-c'><br />        <br />while (xchg(&amp;lock, 1) == 1) {<br />    // busy wait<br />}<br />{}<br />    </code><br /></pre><br /><br /><blockquote>Futexes are not purely user-space: they are a hybrid mechanism that requires both user-space spinning and kernel help to avoid wasting CPU when contended. User space alone cannot safely sleep a thread and wake it later without kernel mediation. This is why futexes are a hybrid: “fast path” in user space, “slow path” in kernel.</blockquote><br /><br /><blockquote>The internal lock used by </blockquote><blockquote><code>libdispatch</code></blockquote><blockquote> is named dispatch_lock (without the _t suffix) in private headers, while Actor uses “</blockquote><blockquote><code>dispatch_lock_t</code></blockquote><blockquote>” descriptively to refer to that internal lock identity encoding, not to a public typedef. It’s a user‑space lock built on atomic word updates that, under contention, park and wake threads via a futex‑style OS interface provided by libdispatch on Darwin; this is kernel‑assisted waiting, not a Mach message–level lock, and Swift actors record a dispatch lock identity in </blockquote><blockquote><code>ActiveActorStatus</code></blockquote><blockquote> to enable priority escalation of the running thread;</blockquote><br /><br />Normal synchronization is via atomic state transitions on <code>ActiveActorStatus</code> and the actor’s serial executor semantics; the <code>DrainLock</code> records the running thread’s identity so the runtime can boost/deboost it, not to guard a critical section with a user-level mutex in the steady state. This design lets the runtime avoid per-call retains/releases and heavy locks while still providing priority-inversion mitigation by escalating the thread currently “holding” the actor, as indicated by the <code>DrainLock</code> identity field;<br /><br />An actor instance embeds runtime state that can keep it alive while work exists, either via the normal <code>ActiveActorStatus</code> path or, under a special build flag, via a lock and a separate lock reference count, so memory is only freed once the queue/lock lifecycle is finished in addition to object deinit conditions.<br /><br />Continued in the comments below.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-09-03T18:39:23+00:00"}, {"id": "https://t.me/c/2068344133/325", "url": "https://t.me/c/2068344133/325", "title": "➕ If you’re a student choosing what to focus on, pick MATH. It will teach you to relentlessly rely o", "content_html": "➕ If you’re a student choosing what to focus on, pick MATH. It will teach you to relentlessly rely on your own brain, think logically, break down problems, and solve them step by step in the right order. That’s the core skill you’ll need to build companies and manage projects. 🏢", "date_published": "2025-07-12T06:22:24+00:00"}, {"id": "https://t.me/c/2068344133/324", "url": "https://t.me/c/2068344133/324", "title": "#swift #concurrency #underthehood   Demystifying the Thread Cap of Swift Concurrency’s Cooperative T", "content_html": "#swift #concurrency #underthehood <br /><br /><strong>Demystifying the Thread Cap of Swift Concurrency’s Cooperative Thread Pool</strong><br /><br />В директ порою прилетают интересные вопросы, на все развернуто я не могу ответить. Часть полезная информация остается за кадром. <br /><br />Вопрос: <br /><blockquote>“… Каким количеством потоков оперирует Swift Concurrency? …”. </blockquote><br /><br /><em>Тривиальный</em> ответ и он не очень <em>грубой</em> ложью будет:<br /><br /><blockquote>“thread per core to minimize context switch and efficiently utilize compute resources”; </blockquote><br /><br />Но есть пара примечательностей (!). На 16 ядерной машине, без хаков, можно запустить 64 потока на SC. На скрине тривиально показаны 54 потока. Все дело в… Mach kernel, TaskPriority и Darwin-executors: higher-priority таски, планируются на higher-priority pthread’ах Mach kernerl’ом. Таким образом SC позволяет, при определенном стечении обстоятельств, когда low priority задача попадают в одну из 4 выделенных очередей-бакетов, перед более выско-приоритетными задачами, запустить следующее количество потоков:<br /><br />(per CPU core) thread per dedicated quality-of-service bucket<br /><br />WTF is quality-of-service bucket? Почему 4? Это выделенный бакет для групп кросс-aliased QoS. Если вы посмотрите на количество приоритетов, которые можно передать Task то их будет 6 (.utility, .background, .low, .medium/.default, .high, .userInitiated). Эволюционно часть из них артефакты, с точки зрения планировщика их 4, а в Mach kernel определены приоритеты от 0 до 63 (примечательно?), <a href=\"https://github.com/swiftlang/swift/blob/a9f696b812612042f595538807877e4efc57c5cf/stdlib/public/Concurrency/Task.swift#L308\">а в TaskPriority они определен следующим образом</a>:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />public struct TaskPriority: RawRepresentable, Sendable {<br />  public typealias RawValue = UInt8<br />  public var rawValue: UInt8<br /><br />  public init(rawValue: UInt8) {<br />    self.rawValue = rawValue<br />  }<br /><br />  public static let high: TaskPriority = .init(rawValue: 0x19)<br /><br />  @_alwaysEmitIntoClient<br />  public static var medium: TaskPriority {<br />    .init(rawValue: 0x15)<br />  }<br /><br />  public static let low: TaskPriority = .init(rawValue: 0x11)<br /><br />  public static let userInitiated: TaskPriority = high<br />  public static let utility: TaskPriority = low<br />  public static let background: TaskPriority = .init(rawValue: 0x09)<br /><br />  @available(*, deprecated, renamed: &quot;medium&quot;)<br />  public static let `default`: TaskPriority = .init(rawValue: 0x15)<br />}<br />{}<br />    </code><br /></pre><br /><br />• <code>userInitiated</code> это alias для <code>high</code><br />• <code>utility</code> это alias для <code>low </code><br />• <code>default</code> вообще рудимент и уже давно <code>.medium</code>;<br /><br />Essentially 4 приоритета (по этому и cross-aliased дабы интуитивно не подумать, что для всех QoS), где для каждого выделяется своя очередь потоков aka dedicated quality-of-service buckets. <br /><br />Если перевести из hexadecimal в decimal, то можно получить некоторый меппинг приоритетов в числовом виде:<br /><br /><blockquote>background -&gt; 0x09 -&gt; 9<br />low / utility -&gt; 0x11 -&gt; 17<br />medium / default -&gt; 0x15 -&gt; 21<br />high / user initiated -&gt; 0x19 -&gt; 25</blockquote><br /><br />И того для 16 ядерном CPU имеем:<br /><br /><blockquote>16 (CPU cores) * 4 (dedicated quality-of-service queues) = максимально возможные 64 потока в cooperative thread pool, без GCD очередей, 100% средствами SC.</blockquote><br /><br />Есть примечательная особенность, когда в диспатче не происходит overcommit’a, более приоритетные задачи выполняются в своей кооперативной очереди, каждая на отдельном потоке (скажем у нас 16 CPU Cores), то другие кооперативные очереди с более низким приоритетом запускают по одной задачи на припаркованных потоках. Как правило, эвристически будет 16 + 3 потоков + 1 поток для Main Actor, но он не в пуле; <br /><br />В итоге мы получаем, so called “thread overcommitting”, а не thread explosion:<br /><br /><blockquote>Generally: Overcommit refers to its policy of launching extra threads when all worker threads are busy or blocked and more work arrives;</blockquote><br /><br />Продолжение в комментах.<br />↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-07-10T17:23:01+00:00"}, {"id": "https://t.me/c/2068344133/323", "url": "https://t.me/c/2068344133/323", "title": "#typesystem #swift #compiler #llvm  Type System: Conformance Substitution &amp; Projection  Как вся ", "content_html": "#typesystem #swift #compiler #llvm<br /><br /><strong>Type System: Conformance Substitution &amp; Projection</strong><br /><br />Как вся эта неоднозначность, из прошлого поста, в декларациях разрешается на уровне компилятора? Какие конкретно подкопотные механизмы позволяют делать столь гибкую, но в тоже время типо-безопастную подстановку типов? - Conformance substitution map и Projection, через self-consistent алгебру (про это отдельно*);<br /><br />• Основной ADT (abstract data type) или структура данных для преобразования sugared / abstract type declarations в конкретные, материализованные типы;<br />• Сам по себе substitution map необходим для тайп-чекеру для оперирования над референсами дженерик деклараций, специализированном через generic argument list. Об этом я коротко писал в одном из ~20 постов про систему типов. Абстрактно, substitution map (карта подстановки/замещения) определяет тип-замещение путем рекурсивной аппликации substitution map’a к interface type дженерик декларации, замещая параметры и материализуя тип через специализированный референс; <br />• Схематично, substitution map хранит input generic signatures и generic signature’s list дженерик параметров, где conformance requirements определяют форму substitution map’ы. <br /><br />Примечательно #1: для type witnesses из предыдущего поста синтезируется conformance substation map через механизм известный как projection π([L]A) (где A это associated type декларированный в протоколе L), где type witness projection это self-consistent алгебра; Type wines может декларировать свой дженерик аргумент-список (e.i. &lt;T,…&gt;) в качестве произвольного типа-интерфейса (arbitrary interface type), то projection будет:<br /><br /><blockquote>π([L]A)⊗[T: P] := W</blockquote><br /><br />Где:<br />• [L]A - protocol type L и его associated type A<br />• W - номинальный type witness, представляющий конкретный тип<br />• [T: P] - конформанс типа T протоколу P<br /><br />Или:<br /><blockquote>if [Td: L]∈Conf(G), then π([L]A)⊗[Td: L] ∈ Type(G)</blockquote><br /><br />Где каждый projection будет:<br />• π([L]T)⊗[WithMemberType: L] = WithMemberType.T<br />• π([L]T)⊗[WithGenericParam: L] = τ_0_0<br />• π([L]T)⊗[WithInferredType: L] = String<br />• π([L]T)⊗[WithDefault: L] = Int<br /><br />Или:<br />• Σ1 := {T→WithMemberType.T}<br />• Σ2 := {T→τ_0_0}<br />• Σ3 := {T→String}<br />• Σ4 := {T→Int}<br /><br />Примечательно #2: generic placeholder types после разсахаривания компилятором становятся парой индексов, определенных через τ_0_0. То есть struct T&lt;V&gt; { } -&gt; struct T&lt;τ_0_0&gt; { }, где первый индекс порядковый, а второй - индекс нестинга, то есть описывающий глубину деклараций. Вы можете видеть это в некоторых диагностиках в Xcode, кода тайп-чекер начинает заикаться;<br /><br />То есть type witness специализированного конформанса полностью и однозначно определяется, через его underlying конферанс и conformance substitution map:<br /><br /><blockquote>π([A]T)⊗[T: L] = π([L]A)⊗ [Td: L]⊗Σ = π([L]A) ⊗[Td: L]⊗Σ</blockquote><br /><br />Type witness и специализированные конформансы, схематично вы можете видеть на прикрепленном медиа. Evaluation order для разрешения конформансов так же имеет три вида, но сами по себе уже выходят за рамки поста-заметки;<br /><br />• Substitution maps всегда иммутабельны и содержат уникальные типы, так же как типы и дженерик сигнатуры;<br />• Substitution maps проходят каноникализацию путем конструирования нового substitution map’a, если все replacement типы каноничны и их все конформансы так же каноничны;<br />• Substitution map может иметь identity форму - это когда каждый параметр типа-декларации мепится в самого себя, изменяя архетип контекстного типа, замещая его на архетип с эквивалентными type parameters  -&gt; что ведет к forward substitution map;<br />• Substitution map может быть пустым, если валидный интерфейс-тип определен полностью и конкретно: Int⊗{}= Int;<br /><br />Композиция substation maps - это то что происходит когда вы объявляете типы связные через дженерик декларации, как это было в примерах выше. В этом случае множество substitution maps объединяются в одну общую, через некоторую функцию подстановки. Это весьма нетривиально, где в основе лежит теория категорий (category theory): где функциии подстановки выражается через морфизм. <br /><br />Продолжение в комментах. <br />↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-06-30T17:03:50+00:00"}, {"id": "https://t.me/c/2068344133/322", "url": "https://t.me/c/2068344133/322", "title": "#typesystem #swift #compiler #llvm  Type System: Many Faces of Type Witness  Связные посты - как с ф", "content_html": "#typesystem #swift #compiler #llvm<br /><br /><strong>Type System: Many Faces of Type Witness</strong><br /><br />Связные посты - как с формальной, так и с имплементационной и с прикладных перспектив:<br /><br />• <a href=\"https://t.me/contravariance/203\">Type System: Protocol Types</a><br />• <a href=\"https://t.me/contravariance/204\">Type System: Protocol Types II</a><br />• <a href=\"https://t.me/contravariance/287\">Type System: Type Witness &amp; Curry-Howard Correspondence</a><br /><br />Фулфилмент (fulfilment) каждого из обязательных (required) деклараций протокола через конкретный тип - это и есть type witness; <br /><br /><pre><br />    <code class='language-swift'><br />        <br />protocol L {<br />    associatedtype T = Int<br />    func f(_: T)<br />}<br />extension L {<br />    func f(_: T) {}<br />}<br />{}<br />    </code><br /></pre><br /><br />Концептуально, выражается это может в одной из 4 форм (на самом деле лексически, алгебра позволяет выражать сильно больше):<br /><br />1. Через member type declarations в форме подстановки (substitution, концептуально можно понимать, через призму shadowing) поверх ассоциированного значения. Как правило member type это type alias, но что примечательно #1 так это то что мы можем декларировать вложенный номинальный тип в качестве той самой подстановки декларации. Если конформящий тип класс (class), то member type может декларирован и как композоитный тип суперкласса (superclass):<br /><br /><pre><br />    <code class='language-swift'><br />        <br />struct WithMemberType: L {<br />    struct T {}<br />}<br />{}<br />    </code><br /></pre><br /><br />Это легальный type witness для протокола L. Что примечательно #2 так это то, что typealias никуда не девается, он все равно синтезируется, но в данном кейсе через материализацию композитного номинального типа T. <br /><br />2. Через primary associated type aka <em>дженерик</em> протокол:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />struct WithGenericParam&lt;T&gt;: L {<br />    // synthesized: typealias T = T<br />}<br />{}<br />    </code><br /></pre><br /><br />К моему удивлению очень многие не знают (примечательно #3 лол), что в Swift 5.7 появились те самые PwPATs и решают одно из давних ограничений для same type requirements <a href=\"https://github.com/swiftlang/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md\">SE-0346 Lightweight same-type requirements for primary associated types</a>.<br /><br />3. Associated type interface может быть материализован неявно, через derived type declaration:<br /><br /><pre><br />    <code class='language-swift'><br />        <br />struct WithInferredType: L {<br />    // synthesized: typealias T = String<br />    func f(_: String) {}<br />}<br />{}<br />    </code><br /></pre><br /><br />Подкапотно, подобный синтезис весьма комплексный, если вы вдруг решите разложить все на атомы или написать свой conformance synthesis механизм.<br /><br />4. Фолбек на дефолную декларацию ассициированного типа: <br /><br /><pre><br />    <code class='language-swift'><br />        <br />struct WithDefault: L {<br />    // synthesized: typealias T = Int<br />}<br />{}<br />    </code><br /></pre><br /><br />Что примечательно #4, при conformance substation lookup, если все остальные механизмы фейлятся, то это дефолт. Если тут быть не внимательным или у вас комплексная система, то вы случайно можете вывести неожиданный тип. Это будет логическая ошибка программиста, но она этим же максимально опасна: ее отладка будет весьма и весьма проблемной, у вас (вероятно) не будет ни краша, ни warning’a, лишь логическое несоответствие типов, что в силу абстрактной природы не всегда мягко говоря очевидно.<br /><br />Продолжение во Conformance Substitution &amp; Projection.<br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-06-30T17:00:48+00:00"}, {"id": "https://t.me/c/2068344133/321", "url": "https://t.me/c/2068344133/321", "title": "#offtopic #liquidglass #metal  Друзья всех приветствую!   Много новых людей, о себе скажу лаконично:", "content_html": "#offtopic #liquidglass #metal<br /><br /><strong>Друзья всех приветствую! </strong><br /><br />Много <em>новых людей</em>, о себе скажу лаконично: я не публичный человек, но волей случая и моей где то неосмотрительности я начал делится некоторыми заметками на канале. Вот собственно и все. <br /><br />Я чуток умею программировать и делюсь этим, иногда относительно нетривиальных топиков, рандомно но, пока пишу больше про: компилятор, эволюцию Swift, системы типов, конкурентность, DSA, Metal &amp; CG и не педагогически френдли (весьма); <br />Хотя мне уважаемые люди с Купертино сказали, что очень доступно все 🫶. Не важно где вы и откуда, мне все равно на ваши беджики и вообще любые атрибуты - если вы любите программирование и можете цивилизованно общаться - hello, всем!<br /><br /><blockquote>Далее будут <em>маленько</em> нетривиальные посты, не пугайтесь, цель всегда была просто поделиться чем то, а что с этим делать или не делать - это уже на ваше усмотрение. Но пусть это вашу жажду к знаниям только разогреет!<br /></blockquote><br /><br /><blockquote>Если хотите напишите немного, о себе в комментах - будет возможность друг с другом познакомится</blockquote><br /><br />@contravariance<br /><video controls poster=\"https://tg.davvie.com/static/-1002068344133--321-0.mp4\" style=\"max-width:100%;\"><source src=\"https://tg.davvie.com/static/-1002068344133--321-0.mp4\" type=\"video/mp4\">Your browser does not support the video tag.</video>", "date_published": "2025-06-30T16:42:17+00:00", "attachments": [{"url": "https://tg.davvie.com/static/-1002068344133--321-0.mp4", "mime_type": "video/mp4"}]}, {"id": "https://t.me/c/2068344133/320", "url": "https://t.me/c/2068344133/320", "title": "#swift #android  Swift is coming to Android! 😳   С другой стороны Embedded Swift (подмножество) появ", "content_html": "#swift #android<br /><br />Swift is coming to Android! 😳 <br /><br />С другой стороны Embedded Swift (подмножество) появился в небольших количествах в Darwin kernel в бетах;<br /><br />• <a href=\"https://swift.org/android-workgroup/\">https://swift.org/android-workgroup/</a><br />• <a href=\"https://forums.swift.org/t/announcing-the-android-workgroup/80666\">https://forums.swift.org/t/announcing-the-android-workgroup/80666</a><br /><br />P.s. в workgroup входит Saleem Abdulrasool <a href=\"https://forums.swift.org/u/compnerd/summary\">(@compnerd)</a> - кто знает, тот знает 🙃<br /><br />@contravariance<br /><img src=\"https://tg.davvie.com/static/-1002068344133--320-0 (1).jpg\" alt=\"media\"/>", "date_published": "2025-06-26T05:49:59+00:00", "attachments": [{"url": "https://tg.davvie.com/static/-1002068344133--320-0 (1).jpg", "mime_type": "image/jpeg"}]}, {"id": "https://t.me/c/2068344133/319", "url": "https://t.me/c/2068344133/319", "title": "#typesystem #swift  Type Systems: @lifetime dependencies   Одним из весомых нововведений в систему т", "content_html": "#typesystem #swift<br /><br /><strong>Type Systems: </strong><strong>@lifetime</strong><strong> dependencies <br /></strong><br />Одним из весомых нововведений в систему типов Swift будет @lifetime dependencies. Пропозал пока на стадии разработки, но заимплементен в 6.2 под флагом LifetimeDependence ибо это экспериментальная фича.<br /><br />Концептуально: @lifetime это новый атрибут для явной аннотации деклараций эмитящие ~Escapable значения или статический энфорсмент между типом-продюсером и типом-консьюмером. Можно описывать зависимости типов на уровне жизненного цикла, пролонгировать их или же напротив - ограничивать уничтожение. Изменение намного более комплексное, работает вкупе c ownership системой, но учитывает ARC. <br /><br /><pre><br />    <code class='language-swift'><br />        <br />struct Container&lt;Element: ~Escapable&gt;: ~Escapable {<br />  var element: Element<br /><br />  @lifetime(copy element)<br />  init(element: Element) {<br />    self.element = element<br />  }<br /><br />  @lifetime(copy self)<br />  func getElement() -&gt; Element {<br />    element<br />  }<br />}<br /><br />extension Container: Escapable where Element: Escapable { }<br />{}<br />    </code><br /></pre><br /><br />• <strong>@lifetime</strong><strong>(copy element) init</strong>: результат инициализации контейнера аннотируется и наследуюет лайфтайм отдельного элемента (element) и более того пропагирует лайфтайм на протяжении всех использований этого проперти. Это означает, что Container не сможет пережить element и гарантирует безопасную связь <br />• @<strong>lifetime</strong><strong>(copy self) func getElement()</strong>: метод возвращает со-зависимый от самого Container элемент; это выражает концепцию borrow-lifetime, где консьюмер (getElement()) гарантирует, что возвращённый Element жив, пока жив сам контейнер.<br /><br /><blockquote><a href=\"https://t.me/contravariance/199\">Про ~Escapable типы я писал ранее.</a> Даже писал немного чем являются данный вид suppressible протоколов / quasi-protocols на имплементационном уровне. <br /></blockquote><br /><br />Lifetime dependencies - это не про линейные типы, хотя есть некоторые черты. Понимать можно через призму affine-style semantics с borrowed lifetimes - хотя сейчас через @lifetime можно и consuming relationships описывать - ненулевая вероятность, что это поменяется;<br /><br /><blockquote>Тривиально:<br />• Линейные типы - каждое значение может быть использовано ровно один раз, без копирования / early discarding;<br />• Аффинные типы - каждое значение может быть использовано не более одного раза, без копирования / early discarding;<br /></blockquote><br /><br />Свифтовая модель - гибридная аля affine-style/scoped types with borrow semantics и нет Swift не копирует Rust. Вообще ортогонально, Swift <del>дольше находится в разработке</del> первая версия раньше увидела свет и акценты совершенно другие в языке(у Mozilla не хватает деняк такое делать :p). Формально эта связка, через type systems будет affine substructural types with borrowed lifetimes / explicit lifetime consumtion или энфорсятся substrcutural typing by restricting structural rules. Комплексно да, красиво, под прикладные задачи завозят, в общем все хорошо;<br /><br />За счёт этого affine-типы ↔ affine substructural typing (с ослаблением contraction, но с weakening);<br /><br />Доводится до ума будет какое то время, а это история минимум до версии Swift 6.6+ система типов весьма сильно преобразится, надеюсь и верю. И да, язык проще не станет, но это opt-in фича, где есть симметричный и самое главное приемлемый дефолт для большинства юзкейсов.<br /><br />@contravariance", "date_published": "2025-06-17T14:41:12+00:00"}, {"id": "https://t.me/c/2068344133/318", "url": "https://t.me/c/2068344133/318", "title": "#papers #llm  Долго ждать не пришлось, ребята из MIT (преимущественно) провели масштабное исследован", "content_html": "#papers #llm<br /><br />Долго ждать не пришлось, ребята из MIT (преимущественно) провели масштабное исследование влияния LLM на некоторые когнитивные функции мозга. На 206 страницах подробно изложена методология и результаты. Примечательно, тех кто полагается только на свой мозг обозначили как brain-only. <br /><br />То что будет с вашим мозгом происходить зависит только от вас, сама по себе LLM лишь очередная дофаминовая игла (одна из перспектив), коих в мире миллион. Парадокс в том, что эта игла может стать весьма мощным инструментом, стоит только найти применение и обрести баланс.<br /><br /><blockquote>…<br />EEG revealed significant differences in brain connectivity: Brain-only participants exhibited the strongest, most distributed networks; Search Engine users showed moderate engagement; and LLM users displayed the weakest connectivity.<br />…</blockquote><br /><br /><blockquote>…<br />While LLMs offer immediate convenience, our findings highlight potential cognitive costs. Over four months, LLM users consistently underperformed at neural, linguistic, and behavioral levels. These results raise concerns about the long-term educational implications of LLM reliance and underscore the need for deeper inquiry into AI&#x27;s role in learning.<br />…</blockquote><br /><br /><a href=\"https://arxiv.org/abs/2506.08872\">https://arxiv.org/abs/2506.08872</a><br /><br />@contravariance", "date_published": "2025-06-17T07:08:13+00:00"}, {"id": "https://t.me/c/2068344133/317", "url": "https://t.me/c/2068344133/317", "title": "#fp #unfold #zip #swift #leetcode   Functional Swift: Trivial DSA Applications  Паттерны описанные в", "content_html": "#fp #unfold #zip #swift #leetcode <br /><br /><strong>Functional Swift: Trivial DSA Applications</strong><br /><br />Паттерны описанные в <a href=\"https://t.me/contravariance/301\">zip</a> и <a href=\"https://t.me/contravariance/308\">unfold sequence</a> постах хорошо ложатся на ... субботний литкод ран :). На самом деле я переписывал части AST парсера, отвлекся <em>немного</em>. Тем не менее, нахожу полезным взять скоуп задач разной сложности на литкоде, лимитировать временем и постараться как можно лаконичнее решить их. Но что примечательно, так это то что всего пара FP style паттернов ложатся на абсолютные рандомные задачи, так например в этом ране я взял последние 3 дейлика где удалось выразить все концепции из последних постов:<br /><br />• adjacency pair mapping via zip<br />• binary search via unfold sequence <br />• laconic integer/digits mapping via reduce / unfold sequence <br /><br /><blockquote>Редьюсеры отдельная любовь, наравне с <code>contraMap</code> и <a href=\"https://t.me/contravariance/192\">каррированием,</a> когда их удается применить конечно;</blockquote><br /><br />Небольшие техники начинают играть совсем иначе при более высокоуровневой композиции. По этому считаю критически важным понимать атомы подобных билдинг блоков, вплоть до уровня компилятора и через призму формальных систем типов - ибо это имхо качественно отличает доступные возможности. <br /><br />Есть довольно примечательные развороты алгосов в FP обертке, как например linked list traversal в одну стрчку через unfold sequence, но природа этих алгоритмов уже довольно не тривиальная. Думаю, о многих в принципе сильно меньше говорят, чем о забитых до посинения категориях (аля sliding window, prefix sum, binary search etc.); <br /><br /><blockquote>Про DSA я оказывается тоже можно сказать ничего не писал развернуто. Окак :D<br /></blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-06-14T17:35:37+00:00"}, {"id": "https://t.me/c/2068344133/316", "url": "https://t.me/c/2068344133/316", "title": "#wwdc25 #whatisnew #uikit #swiftui #swift  В целом, по верхушкам: контейнирезация, интероп с Java, г", "content_html": "#wwdc25 #whatisnew #uikit #swiftui #swift<br /><br />В целом, по верхушкам: контейнирезация, интероп с Java, грядущий Swift 6.2 с довольно крутыми изменениями, многое мы смотрели, но в целом пропозалов в эволюции сильно больше;<br /><br />• Опять же Metal 4<br />• Foundation Models<br />• SwiftUI - тут ожидаемо, завезли перф (в виде прифетчинга) и реюз lazy контейнеров, general improvements, 3d charts, Animatable macro<br />• Сompilation caching build setting в Xcode<br />• Ну а так же UIKit и он получил весьма ощутимые изменения (было забавно читать, как его очередной год отменяют): контейнеры, инспекторы, изменения в menu bar в частности в iPadOS и ... architectural improvements: observable objects теперь в ките, automatic UI invalidation, automatic trait tracking, и что то даже back-deployed до iOS 18 (через ключ UIObservationTrackingEnabled: YES в .plist):<br />    • New UI update methods (updateProperties() on UIView &amp; UIViewController) - called just before layoutSubviews() but fully independent - use to set properties of views and controllers that don&#x27;t involve layout;<br />    • В общем Obsevation плотно завязан в UI layer теперь<br />    • New .flushAnimation / .flushUpdates option - auto-updates views when animation context changes, now we can change state and perform invalidations inside animation closures; Можно юзать с констрейнтами<br />    • Scene updates: use SwiftUI scenes with UIKit application, UIHostingSceneDelegate; New trait for HDR content;<br /><strong>    • Обновления Notification Center: теперь - <del>stringly</del> strongly</strong> (!!!)<strong> typed</strong>, improved support of swift concurrency;<br /><br />@contravariance", "date_published": "2025-06-10T08:09:13+00:00"}, {"id": "https://t.me/c/2068344133/315", "url": "https://t.me/c/2068344133/315", "title": "#wwdc25 #metal #liquidglass  Новый компилятор был представлен для Metal 4:  + new command encoder, p", "content_html": "#wwdc25 #metal #liquidglass<br /><br />Новый компилятор был представлен для Metal 4:<br /><br />+ new command encoder, pipeline &amp; shared compilation results, чем могли по полной воспользоваться при столь радикальном техническом изменении по части рендеринга; (в целом сильно больше изменений, не все рендеринга / компьюта касаются, так например добавили тензоры)<br /><br />Примечательно, что UIKit <em>не отменили, </em>а в качестве backing private view для liquid glass используются _UILiquidLensView с набором кастомных CoreImage фильтров включающие displacement map &amp; glass effect kernels;<br /><br /><blockquote>Эффект удалось повторить, с некоторой степенью приблежения, но вся его работа не заканчивается только лишь рендеренгом: там очень много подкапотной + алгоритмической <em>магии</em> для полноценного interaction design UX + motion, morphing, alpha blending симулирующий blob-like morphing (в телеги когда профиль скролите например). Рефракция учитывает геометрию, закругление углов и морфинг. Если результат будет презентабельным, то опенсоурсну (без обещаний);</blockquote><br /><br />@contravariance<br /><strong>The video is too large.</strong>", "date_published": "2025-06-10T07:35:12+00:00"}, {"id": "https://t.me/c/2068344133/314", "url": "https://t.me/c/2068344133/314", "title": "#wwdc25 #swift #concurrency  Must-watch сессия от Симы @sima_stories 👏  https://developer.apple.com/", "content_html": "#wwdc25 #swift #concurrency<br /><br />Must-watch сессия от Симы @sima_stories 👏<br /><br /><a href=\"https://developer.apple.com/videos/play/wwdc2025/270\">https://developer.apple.com/videos/play/wwdc2025/270</a><br /><br />@contravariance<br /><img src=\"https://tg.davvie.com/static/-1002068344133--314-0.jpg\" alt=\"media\"/>", "date_published": "2025-06-09T21:55:07+00:00", "attachments": [{"url": "https://tg.davvie.com/static/-1002068344133--314-0.jpg", "mime_type": "image/jpeg"}]}, {"id": "https://t.me/c/2068344133/313", "url": "https://t.me/c/2068344133/313", "title": "#wwdc25   New window manager / tiling и background tasks на iPad прям топ 🔥  @contravariance", "content_html": "#wwdc25 <br /><br />New window manager / tiling и background tasks на iPad прям топ 🔥<br /><br />@contravariance", "date_published": "2025-06-09T18:26:22+00:00"}, {"id": "https://t.me/c/2068344133/311", "url": "https://t.me/c/2068344133/311", "title": "#wwdc25  Light refraction компьютится быстрее на GPU чем в среднем блюр, так шо не переживайте по по", "content_html": "#wwdc25<br /><br />Light refraction компьютится быстрее на GPU чем <em>в среднем</em> блюр, так шо не переживайте по поводу liquid glass design;<br /><br />Как правило это screen space refraction - cложность в основном связана с поиском преломленного луча и выбором текстур для отображения. Для простых материалов (стекла) это часто дешевле, чем сложные свертки vs gaussian blur, где юзаются конволюции, что требует нескольких проходов по пикселям;<br /><br />Эффект формируется так же из specular highlights aka concentrated reflections of light sources, а так же можно добавить немного chromatic aberration aka prismatic effect ближе к границам / рефракционным зонам; <br /><br /><blockquote>Асимптотически, через Big O:<br />• Refraction + reflections + chromatic aberration = O(n) per fragment<br />• Gaussian blur = O(n•k²) (при наивной 2D свeртке) и O(n•k) (при раздельном (separable) ядре) per fragment</blockquote><br /><br />Все равно будет быстрее;<br /><br /><blockquote>⚠️ Actual implementation details естественно проприетарные</blockquote><br /><br />@contravariance", "date_published": "2025-06-09T17:17:06+00:00"}, {"id": "https://t.me/c/2068344133/310", "url": "https://t.me/c/2068344133/310", "title": "#llm #lrm #papers  Занимательное чтиво.  Про перемножение матриц в двух актах. +/- в одно и тоже вре", "content_html": "#llm #lrm #papers<br /><br /><strong>Занимательное чтиво.<br /></strong><br />Про <em>перемножение матриц</em> в двух актах. +/- в одно и тоже время дропаются две независимые научные работы <em>somewhat коррелирующие</em> между собой. <br /><br />В первой работе посчитали (<a href=\"https://arxiv.org/abs/2505.24832\">How much do language models memorize?</a>), что каждый параметр LLM способен “запомнить” примерно 3.6 бит информации (в информационной теории по Колмагорову-Шенону) - это свойство определяет момент перехода от запоминания в генерализацию, то есть когда объем данных в битах примерно равен общей емкости модели или fp16 - примерный потолок того что нужно на прикладном уровне в текущих реалиях. Более плотная квантизация возможна, если данные, с которыми работает модель, обладают достаточной структурной избыточностью или устойчивостью к шуму;<br /><br />Во второй, Apple дропает перед даб-дабом довольно занимательный paper на тему ограничений LRMs (Large Reasoning Models) и LLMs. Я не буду сильно ее комментировать, <em>дабы не создавать бурю в стакане</em>. У работы довольно говорящее название: <a href=\"https://machinelearning.apple.com/research/illusion-of-thinking\">The Illusion of Thinking: Understanding the Strengths and Limitations of Reasoning Models via the Lens of Problem Complexity</a>. Файндинги весьма примечательные, где то ожидаемые: Америку не открыли, но в ажиотаж добавили немного рационального скептицизма;<br /><br /><blockquote>…we show that frontier LRMs face a complete accuracy collapse beyond certain complexities. Moreover, they exhibit a counter-intuitive scaling limit: their reasoning effort increases with problem complexity up to a point, then declines despite having an adequate token budget. By comparing LRMs with their standard LLM counterparts under equivalent inference compute, we identify three performance regimes: (1) low-complexity tasks where standard models surprisingly outperform LRMs, (2) medium-complexity tasks where additional thinking in LRMs demonstrates advantage, and (3) high-complexity tasks where both models experience complete collapse. We found that LRMs have limitations in exact computation: they fail to use explicit algorithms and reason inconsistently across puzzles. …<br /></blockquote><br /><br />Ставьте 🤯 или 🔥 если, как в работе Apple задача на Ханойские башни с доп условиями вас тоже <em>сломала</em>, но привила чувство прекрасного при <a href=\"https://t.me/contravariance/308?comment=442\">выводе рекуррентного соотношения</a> 🗿;<br /><br />@contravariance", "date_published": "2025-06-08T13:15:24+00:00"}], "icon": "https://tg.davvie.com/static/avatars/contravariance.jpg"}