Блог* – Telegram
1.9K subscribers
3.46K photos
135 videos
15 files
3.7K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
Forwarded from Ahoy Senpai~
👍4🌚4😁3
Forwarded from Ahoy Senpai~
👎8❤‍🔥3🤮1🌚1
Подписчики, чат канала подвёргся внезапному наплыву новых пользователей. Обычно это означает массированную спам-атаку. Во избежание неудобств я временно закрыл публичный доступ к Чат*у.

Также я скопом удалил всех новых участников чата. Если вдруг я удалил кого-то из реальных людей, не ботов — пишите в личку (ссылка в описании канала), разберёмся в частном порядке

UPD: волна вроде кончилась, Чат* снова открыт
👍5😢1
Блог* pinned «Подписчики, чат канала подвёргся внезапному наплыву новых пользователей. Обычно это означает массированную спам-атаку. Во избежание неудобств я временно закрыл публичный доступ к Чат*у. Также я скопом удалил всех новых участников чата. Если вдруг я удалил…»
Ей-богу, когда-нибудь я удалю канал, просто случайно нажав не туда
🌚11💯5❤‍🔥3😱3
#gamedev #video

Alexis Kennedy out of context

Source
😁4
Ужас какой.

Как будто там есть, за чем следить.
❤‍🔥5😁1
🌚18❤‍🔥3
#meme про экзамены
Forwarded from shitposting 3.0 [+ dragons]
🔥10😁7😱3🤯1
Так, блэт, почему уже три (если я не сбился со счёта) человека изъявили желание, чтобы я был их daddy? 🤔
21🌚3🤷2
#prog

Опыт работы с VSCode Live share
Forwarded from концлагерь "закат-13" [экстремист edition]
почему я его ненавижу. спешу отметить, что это мое личное мнение, вероятно, я дурачок, и некоторые из проблем возможно все таки можно решить.

итак, сам список:
• дерганная работа — в direct-режиме и даже если пинг между участниками низкий задержка при использовании live share может составлять несколько секунд. почему? черный ящик имени майкрософта.
десинк порой настолько сильный что у хоста вместо написанного мной кода — каша.

• невозможность поднять свой релей — issue закрыт как "not planned"

• кривая работа с кодом — тайпинги прогружаются через раз, Quick Fix работает, упаси дьявол, 1 раз из 10.
а если ты через тот же Quick Fix пытаешься импортировать какой-то файл — удачи, бро, велик шанс, что он не увидит, где можно импорт взять (даже если он в локальном файле а не в стороннем модуле)

• кривая работа с терминалом — он может тупо зависнуть, если происходит какая-то активная фигня (например — сборка докер имеджа). то какое решение?
либо переподключиться, либо попросить хоста (если это не ты) открыть другой термниал. очень удобно 👍

ну и для нотки лирики: за 2 часа парного кодинга мне пришлось переподключаться около 6-7 раз.
🤮1
😡
🤮4👍3🤬2👌2🔥1
#prog #ocaml #article

Oxidizing OCaml (1, 2, 3) — серия из трёх статей, описывающая дополнения в OCaml, позволяющие добавить в язык некоторые из присущих Rust концептов — владение, лайфтаймы и уникальные ссылки — и таким образом привнести довольно конкретные преимущества для написания корректных и более экономно использующих ресурсы программ. Всё это — через систему аннотаций режимов (mode), ортогональных системе типов и друг другу и потому не влияющих на разрешимость вывода типов (для авторов предложенных изменений это важно).

Настоятельно советую прочитать оригинальные статьи, но что-то я перескажу и тут.

Первая статья: Oxidizing OCaml: Locality. В ней рассказывается про режим локальности значений. В отличие от полиморфных ссылок Rust, этот режим поддерживает лишь два возможных варианта: global (вариант по умолчанию) и local.

Времена жизней глобальных (global) значений могут жить независимо от исполнения различных функций. Как следствие, компилятор вынужден все подобные значения класть в кучу и делегировать управление временем их жизни рантаймовому сборщику мусора. На использование локальных (local) значений накладываются ограничение: именно, подобные значения не могут пережить функцию, в которой они находятся. В терминах escape analysis это значения, которые не escape текущую функцию. Так как подобные ограничения излишне строги, язык предоставляет возможность явно выделить local значение во внешнем регионе вместо текущего. Так как escape analysis — это не какая-то новая вещь, определить локальные значения возможно статически во время компиляции.

Введение этого режима даёт два преимущества.

Во-первых, локальные значения можно выделять на стеке — и в случае OCaml это несколько более существенное преимущество, поскольку стековый аллокатор не обязан использовать под стек ту же память, что и стек потока управления. Это позволяет достигнуть более высокой производительности, поскольку использование стекового аллокатора не триггерит использование сборщика мусора, а также естественный LIFO паттерн доступа к стековой памяти приводит к лучшей утилизации кеша процессора. Для сравнения, в текущей реализации OCaml сборщик мусора поколенческий, и для младшего поколения используется кольцевой буфер. Малая сборка мусора относительно дешёвая, но каждый объект, который переживает её, уходит в кучу для старых объектов, обход которой дороже. Вдобавок, использование кольцевого буфера повышает шанс, что аллокация новых значений приведёт в вымыванию из кеша старых значений.

Во-вторых, локальность позволяет строить более корректные API. В качестве примера в статье приводится функция Core_unix.with_file. Эта функция принимает на вход имя файла и коллбек. Семантика достаточно проста: функция открывает файл с указанным именем, отдаёт дескриптор коллбеку, после чего закрывает файл и возвращает результат вызова коллбека. Всё бы ничего, но OCaml — не чистый язык, а потому переданный коллбек может захватить внешнее изменяемое состояние и сохранить файловый дескриптор в нём. Попытка воспользоваться этим дескриптором приведёт в лучшем случае к ошибке, а в худшем — к взаимодействию с некоторым другим файлом, если дескриптор будет переиспользован. Локальность позволяет решить эту проблему. Указав режим аргумента коллбека, как local, мы наложили на коллбек требование, что аргумент не утечёт. Таким образом, мы можем быть уверены, что после завершения коллбека аргумент существует лишь в with_file, и потому его можно передать в close, не опасаясь ошибок.

Как вы могли заметить, local лишь накладывает ограничения на использование, а потому, по идее, можно передать global значение туда, где ожидается local значение. И действительно, на вариантах режима локальности есть отношение субтипизации: global является подтипом local.

Автор отмечает, что локальность с успехом используется на практике.
👍92
Вторая статья: Oxidizing OCaml: Rust-Style Ownership. В ней рассказывается о режиме уникальности значений. У этого режима три возможных значения: shared (вариант по умолчанию), exclusive и unique.

Режим shared говорит о том, что на значение существует произвольное количество ссылок. Это не даёт никакой полезной информации, и такое значение вынужденно управляется сборщиком мусора. В OCaml есть такая возможность, как функциональное обновление записи (в Rust есть аналогичная фича с практически идентичным названием):

type 'a box = { x : 'a option }

let clear box =
{ box with x = None }
;;

(* clear имеет тип 'a box -> 'b box *)

Если значение, переданное в clear, является shared, то компилятор вынужден копировать все поля записи и выделять в куче новое значение поля (а также запись целиком). На поле (и на запись) могут существовать ссылки в иных местах программы, поэтому генерируемый код вынужден выделять память под новую структуру, чтобы другой код не мог заметить изменений.

Но что, если ссылка на box существует в единственном экземпляре? В этом случае можно избежать выделения новой структуры и непосредственно поменять значение поля на новое, что и эффективнее копирования самого по себе, и снижает нагрузку на сборщик мусора. Более того, значение может поменять тип (это называется strong function update) — и это не приведёт к проблемам, так как в силу единственности ссылки старый тип никто не увидит. Чтобы удостоверить единственность ссылки, можно пометить значение, как unique. Это аналогично перемещению в Rust, с той разницей, что режимы ортогональны типам.

Помимо повышения производительности, это позволяет делать более корректный интерфейс. В качестве примера в статье приводится API для манипулирования файлами:

type file

val open_ : path:string -> file @ unique
val close : file @ unique -> unit

Использование unique позволяет удостовериться, что к файлу нельзя обратиться после того, как он будет закрыт. Функция для чтения из файла при этом будет записана так:

val read : file @ local -> string

Режим local для аргумента существенен: если его опустить, то вот такой прямолинейный код:

let print_and_close (unique file) =
print_endline (read file);
close file
;;

приведёт к ошибке, поскольку file тут использован неуникальным образом. Функция read без local может потенциально сохранить file где-то ещё и инвалидировать инвариант единственности ссылки. Правильный код будет выглядеть так:

let print_and_close (unique file) =
print_endline (read &file);
close file
;;

, где синтаксис &file используется для снижения режима file до local shared (и называется заимствованием, как и в Rust).

Как можно заметить, понижение unique до shared валидно. И в этом есть смысл: unique означает информацию о наличии единственной ссылки. Эту информацию можно попросту забыть и получить shared. Действительно, unique является подтипом shared, и в частности, следующий код валиден:

let bar (unique x) =
x, x
;;

(* val bar : 'a @ unique -> 'a * 'a *)

Это аналогично тому, как &mut-ссылку в Rust можно привести к &-ссылке.
👍4❤‍🔥1
Тем не менее, такой уникальный доступ временами излишне ограничителен. Пример:

val write : file @ unique -> string -> unit

let write_and_close (unique file) =
write file "data";
close file
;;

Компилятор закономерно жалуется на то, что мы уже использовали file уникально и потому не можем использовать его снова:

5 | close file
^^^^
Error: file is used uniquely so cannot be used twice.

(аналогично растовому value used after move). Для исправления этого недостатка пришлось бы возвращать file из write — что было бы, мягко говоря, не очень удобно. Продолжая параллели с Rust, в Rust функция write принимала бы &mut-ссылку. И этому есть аналог среди режимов уникальности!

Режим exclusive означает, что ссылок на данное значение может быть несколько, но в данный момент времени активна только одна. Это идеально подходит для аргумента write!

val write : file @ local exclusive -> string -> unit

В коде

let write_and_close (unique file) =
write &file "data";
close file
;;

значение file одалживается только одиножды, поэтому синтаксис &file снижает режим до local exclusive. Если бы аргумент был одолжен дважды, то вместо этого произошло бы понижение до local shared. Пример:

val write2 : file @ local exclusive -> file @ local exclusive -> string -> unit

let write_twice (unique x) =
write2 &x &x "data"
;;

Ошибка:

4 | write2 &x &x "data"
^^
Error: found a shared value where an exclusive value was expected.

В OCaml есть возможность явно помечать поля, как мутабельные. Расширение, добавляющее режимы уникальности, также позволяет помечать поля, как exclusive mutable. Это позволяет задействовать реальную мутабельность для functional update, но не позволяет использовать strong function update. В этом есть смысл: exclusive — это временно уникальная ссылка, а потому имеющиеся до её создания ссылки могли бы наблюдать изменение типа. Тут тоже можно провести параллели с Rust: &mut T инвариантна по T.