#gamedev
Прототип игры в 3D-ASCII графике. Вещь несколько бессмысленная, но впечатляющая.
https://www.squidi.net/threep/p083/
Прототип игры в 3D-ASCII графике. Вещь несколько бессмысленная, но впечатляющая.
https://www.squidi.net/threep/p083/
#prog #rust #gamedev
Потрясающий туториал по созданию своего рогалика на расте. Уже больше 70 глав!
https://bfnightly.bracketproductions.com/rustbook/chapter_0.html
Потрясающий туториал по созданию своего рогалика на расте. Уже больше 70 глав!
https://bfnightly.bracketproductions.com/rustbook/chapter_0.html
Блог*
#rust #gamedev С безукоризенной пунктуальностью выкладываю выпуск новостей раст-геймдева за декабрь. Между прочим, пока что самый интересный. https://rust-gamedev.github.io/posts/newsletter-005/
#rust #gamedev
Последующие выпуски:
https://rust-gamedev.github.io/posts/newsletter-006/
https://rust-gamedev.github.io/posts/newsletter-007/ (совсем свежий, всего вчера опубликован!)
Последующие выпуски:
https://rust-gamedev.github.io/posts/newsletter-006/
https://rust-gamedev.github.io/posts/newsletter-007/ (совсем свежий, всего вчера опубликован!)
Rust GameDev WG
This Month in Rust GameDev #6 - January 2020
Welcome to the sixth issue of the Rust GameDev Workgroup’s
monthly newsletter.
Rust is a systems lan…
monthly newsletter.
Rust is a systems lan…
Блог*
#rust #gamedev Последующие выпуски: https://rust-gamedev.github.io/posts/newsletter-006/ https://rust-gamedev.github.io/posts/newsletter-007/ (совсем свежий, всего вчера опубликован!)
Точность — это моё второе имя. Второе, а не первое.
Forwarded from The Wacky Yellow Dog
@aikidos @Psilon
THE RESTRICT CONTRACT
I, [insert your name], a PROFESSIONAL or AMATEUR [circle one] programmer recognize that there are limits to what a compiler can do. I certify that, to the best of my knowledge, there are no magic elves or monkeys in the compiler which through the forces of fairy dust can always make code faster. I understand that there are some problems for which there is not enough information to solve. I hereby declare that given the opportunity to provide the compiler with sufficient information, perhaps through some key word, I will gladly use said keyword and not bitch and moan about how «the compiler should be doing this for me.»
In this case, I promise that the pointer declared along with the restrict qualifier is not aliased. I certify that writes through this pointer will not effect the values read through any other pointer available in the same context which is also declared as restricted.
THE RESTRICT CONTRACT
I, [insert your name], a PROFESSIONAL or AMATEUR [circle one] programmer recognize that there are limits to what a compiler can do. I certify that, to the best of my knowledge, there are no magic elves or monkeys in the compiler which through the forces of fairy dust can always make code faster. I understand that there are some problems for which there is not enough information to solve. I hereby declare that given the opportunity to provide the compiler with sufficient information, perhaps through some key word, I will gladly use said keyword and not bitch and moan about how «the compiler should be doing this for me.»
In this case, I promise that the pointer declared along with the restrict qualifier is not aliased. I certify that writes through this pointer will not effect the values read through any other pointer available in the same context which is also declared as restricted.
Хотел написать что-то по поводу сегодняшней даты, но... Серьёзно, вы же умные люди, вы и так знаете, какой сегодня день. Будет хорошо, если вы поздравите сегодня кого надо. Спасибо.
Блог*
Вот уже который день пытаюсь написать на Rust бинарное дерево, параметризованное глубиной, до которого ветви хранятся напрямую, а при превышении этой глубины хранится само дерево в Box. Каждый раз натыкаюсь на зацикливание при разрешении trait bounds. Обидно.
Попытался сделать через GAT-ы, но фиг вам:
error: type-generic associated types are not yet implemented
#prog #rust #rustlib
Замечательная библиотека для разбора значений на уровне битов. Как ни странно, не от dtolnay.
https://github.com/porglezomp/bitmatch
Замечательная библиотека для разбора значений на уровне битов. Как ни странно, не от dtolnay.
https://github.com/porglezomp/bitmatch
GitHub
GitHub - porglezomp/bitmatch: A Rust crate that allows you to match, bind, and pack the individual bits of integers.
A Rust crate that allows you to match, bind, and pack the individual bits of integers. - GitHub - porglezomp/bitmatch: A Rust crate that allows you to match, bind, and pack the individual bits of i...
#prog #моё
Сегодня я хотел бы рассказать о возможных способах реализации полиморфизма в языках программирования и о том, какие выгоды и издержки они имеют. Disclaimer: я не особо шарю, так что могу наговорить глупостей.
Полиморфизм — это свойство кода обрабатывать данные разных типов единым образом. Замечательная вещь, не так ли? К сожалению, истинно полиморфного кода мало: если полиморфная функция делает что-то помимо тасовки аргументов, рано или поздно нужно будет выполнить операцию, специфичную для конкретного типа. Для того, чтобы исполнить полиморфный код, нужно каким-то образом передать в него эти функции для конкретного типа. О том, как это можно сделать и на какие компромиссы при этом приходится идти, я сегодня и расскажу.
1. ad hoc полиморфизм (aka полиморфизм для бедных). В этом варианте мы не прилагаем никаких специальных усилий к обеспечению полиморфизма: достаточно разрешить иметь в языке перегрузку функций. При подстановке конкретного типа в обобщённый код компилятор ищет перегрузки с соответствующими типами и вставляет нужные вызовы.
Достоинства:
* Легко реализовать.
Недостатки:
* Наличие перегрузки сразу ставит вопрос о том, какая перегрузка более специфичная, что усложняет рассуждения о коде.
* Требует наличия в языке механизма написания кода с отложенной проверкой типов (макросы в C и шаблоны в C++ под это определение в данном контексте подходят).
* Непосредственное следствие из предыдущего пункта: ошибки несоответствия типов ловятся по месту использования, а не по месту определения, что затрудняет отладку кода и написание высокообобщённого кода ("У меня не сошлись типы потому, что я неправильно вызвал функцию или потому. что сама функция определена ошибочно?").
* Сам факт обобщённости затруднительно переносить между границами отдельных единиц компиляции (читай, фиг вам, а не динамическая линковка).
Резюмируя: использовать имеет смысл тогда, когда нет других альтернатив.
Сегодня я хотел бы рассказать о возможных способах реализации полиморфизма в языках программирования и о том, какие выгоды и издержки они имеют. Disclaimer: я не особо шарю, так что могу наговорить глупостей.
Полиморфизм — это свойство кода обрабатывать данные разных типов единым образом. Замечательная вещь, не так ли? К сожалению, истинно полиморфного кода мало: если полиморфная функция делает что-то помимо тасовки аргументов, рано или поздно нужно будет выполнить операцию, специфичную для конкретного типа. Для того, чтобы исполнить полиморфный код, нужно каким-то образом передать в него эти функции для конкретного типа. О том, как это можно сделать и на какие компромиссы при этом приходится идти, я сегодня и расскажу.
1. ad hoc полиморфизм (aka полиморфизм для бедных). В этом варианте мы не прилагаем никаких специальных усилий к обеспечению полиморфизма: достаточно разрешить иметь в языке перегрузку функций. При подстановке конкретного типа в обобщённый код компилятор ищет перегрузки с соответствующими типами и вставляет нужные вызовы.
Достоинства:
* Легко реализовать.
Недостатки:
* Наличие перегрузки сразу ставит вопрос о том, какая перегрузка более специфичная, что усложняет рассуждения о коде.
* Требует наличия в языке механизма написания кода с отложенной проверкой типов (макросы в C и шаблоны в C++ под это определение в данном контексте подходят).
* Непосредственное следствие из предыдущего пункта: ошибки несоответствия типов ловятся по месту использования, а не по месту определения, что затрудняет отладку кода и написание высокообобщённого кода ("У меня не сошлись типы потому, что я неправильно вызвал функцию или потому. что сама функция определена ошибочно?").
* Сам факт обобщённости затруднительно переносить между границами отдельных единиц компиляции (читай, фиг вам, а не динамическая линковка).
Резюмируя: использовать имеет смысл тогда, когда нет других альтернатив.
Блог*
#prog #моё Сегодня я хотел бы рассказать о возможных способах реализации полиморфизма в языках программирования и о том, какие выгоды и издержки они имеют. Disclaimer: я не особо шарю, так что могу наговорить глупостей. Полиморфизм — это свойство кода обрабатывать…
2. Если нам нужно иметь таблицу функций для каждого значения некоего типа, наиболее прямолинейный способ достичь этого — это включить эту таблицу в каждое значение. Так поступают компиляторы всех мейнстримных объектно-ориентированных языков программирования (Java, C#, C++ при использовании классов).
Достоинства:
* Обобщённая функция в скомпилированном коде всего одна для каждой комбинации типов, поэтому итоговый бинарник остаётся достаточно маленьким.
* Если в языке есть интерфейсы, которые могут расширять друг друга, то можно организовать таблицы функций (vtable) таким образом, чтобы vtable для интерфейса
* Нормальная проверка типов: ошибки ловятся в определении обобщённой функции, если функция неправильна определена, и на месте использования при вызове с неправильными типами аргументов.
* Нормально работает с динамической линковкой.
К сожалению, в этом бочонке мёда есть ковш дёгтя:
* (Этот пункт относится главным образом к вышеупомянутым мейнстримным ООП ЯП, которые смешивают наследование интерфейса и наследование данных) Так как размер конкретного типа вызываемой функции неизвестен, аргументы приходится передавать по указателю (это можно обойти, но с весьма нетривиальными ухищрениями), то есть как минимум первое обращение к аргументу косвенное (последующие могут быть напрямую, если данные остались в кеше процессора). Если созданный аргумент выходит за пределы функции, в которой был создан, то его приходится выделять в куче.
* Если мы хотим иметь в языке расширяемые интерфейсы (а мы хотим, чтобы не копипастить всё руками), то мы не можем напрямую включать vtable в само значение, потому что мы не знаем размера этой vtable наперёд. Поэтому обращение к функциям проходит через ещё один указатель. Конечно, если мы знаем, что интерфейс нерасширяем, то мы можем включить эти функции напрямую, но: а) в этом случае upcast сломается; б) vtable будет занимать в кеше место, оставляя меньше места под поля аргумента.
* Если мы хотим иметь возможность реализовывать несколько интерфейсов для типов (а мы хотим), то придётся держать несколько таблиц, и так как их число наперёд неизвестно, то их придётся держать в динамическом списке (+1 индирекция) и при апкасте к разным интерфейсам либо при каждом обращении искать нужную таблицу, либо менять порядок таблиц в рантайме, так что по факту бесплатный upcast мы теряем.
* Так как у каждого отдельного аргумента потенциально своя vtable, мы не можем толком иметь функции вида
* Получить доступ к vtable можно только в том случае, если у нас есть на руках значение нужного типа, поэтому мы не можем иметь функции вида
Достоинства:
* Обобщённая функция в скомпилированном коде всего одна для каждой комбинации типов, поэтому итоговый бинарник остаётся достаточно маленьким.
* Если в языке есть интерфейсы, которые могут расширять друг друга, то можно организовать таблицы функций (vtable) таким образом, чтобы vtable для интерфейса
Bar
, расширяющего интерфейс Foo
, начиналась с vtable интерфейса Foo
. Таким образом можно получить повышающее преобразование (upcast), которое ничего не стоит в рантайме.* Нормальная проверка типов: ошибки ловятся в определении обобщённой функции, если функция неправильна определена, и на месте использования при вызове с неправильными типами аргументов.
* Нормально работает с динамической линковкой.
К сожалению, в этом бочонке мёда есть ковш дёгтя:
* (Этот пункт относится главным образом к вышеупомянутым мейнстримным ООП ЯП, которые смешивают наследование интерфейса и наследование данных) Так как размер конкретного типа вызываемой функции неизвестен, аргументы приходится передавать по указателю (это можно обойти, но с весьма нетривиальными ухищрениями), то есть как минимум первое обращение к аргументу косвенное (последующие могут быть напрямую, если данные остались в кеше процессора). Если созданный аргумент выходит за пределы функции, в которой был создан, то его приходится выделять в куче.
* Если мы хотим иметь в языке расширяемые интерфейсы (а мы хотим, чтобы не копипастить всё руками), то мы не можем напрямую включать vtable в само значение, потому что мы не знаем размера этой vtable наперёд. Поэтому обращение к функциям проходит через ещё один указатель. Конечно, если мы знаем, что интерфейс нерасширяем, то мы можем включить эти функции напрямую, но: а) в этом случае upcast сломается; б) vtable будет занимать в кеше место, оставляя меньше места под поля аргумента.
* Если мы хотим иметь возможность реализовывать несколько интерфейсов для типов (а мы хотим), то придётся держать несколько таблиц, и так как их число наперёд неизвестно, то их придётся держать в динамическом списке (+1 индирекция) и при апкасте к разным интерфейсам либо при каждом обращении искать нужную таблицу, либо менять порядок таблиц в рантайме, так что по факту бесплатный upcast мы теряем.
* Так как у каждого отдельного аргумента потенциально своя vtable, мы не можем толком иметь функции вида
fn<T>(arg1 T, arg T) -> T
, что очень — нет, не так — ОЧЕНЬ сильно ограничивает выразительность системы типов.* Получить доступ к vtable можно только в том случае, если у нас есть на руках значение нужного типа, поэтому мы не можем иметь функции вида
fn default<T>() -> T
и fn from_str<T>(string s) -> T
.