Forwarded from мне не нравится реальность
Хотите добавить знание Rust в своё резюме, но у вас нет даже свободной минутки? Тогда курс «59 seconds to learn Rust» для вас!
YouTube
Rust Programming - Full 59-Second Course for Beginners
Learn how to program in rust in this complete course for beginners. By the end of this course you will be ready for another Rust course.
Code: https://replit.com/@zizyo/rust
Inspired by this code / article: https://opensource.com/article/20/12/learn-rust…
Code: https://replit.com/@zizyo/rust
Inspired by this code / article: https://opensource.com/article/20/12/learn-rust…
Forwarded from Backtracking (Дима Веснин)
про игры как модель мира: в амазоновской MMO New World дефляция, которая противоположность инфляции, стала настолько серьёзной проблемой, что основным способом торговли в игре стал бартер
This type of regression becomes a severe disincentive to players: what’s the point of leveling a profession if you can’t make any money from it? What’s the point of farming for items if they’re not worth any money, and you can’t afford to repair them?
https://blog.playerauctions.com/mmorpg/currency-crisis-in-new-world/
This type of regression becomes a severe disincentive to players: what’s the point of leveling a profession if you can’t make any money from it? What’s the point of farming for items if they’re not worth any money, and you can’t afford to repair them?
https://blog.playerauctions.com/mmorpg/currency-crisis-in-new-world/
PlayerAuctions Blog
Currency Crisis in New World - PlayerAuctions Blog
A Crisis of Coin Players in New World are experiencing a rare economic crisis, at least within the scope of online gaming: deflation . More money is leaving cir
Forwarded from Lil Functor
Длинный блогпост с подробным объяснением тайп констрейнтов в скале. От паттернов использования до собственной реализации.
Как работают эти магические
https://blog.bruchez.name/posts/generalized-type-constraints-in-scala/
Как работают эти магические
<:<
, =:=
, и почему недостаточно обычных тайп баундов. Для меня при изучении скалы это долгое время был один из самых непонятных вопросов.https://blog.bruchez.name/posts/generalized-type-constraints-in-scala/
Erik’s Ponderings
Generalized type constraints in Scala (without a PhD)
Introduction
#prog
На три вещи можно смотреть бесконечно: на горящий огонь, на текущую воду и на то, как у #python-истов горит с
На три вещи можно смотреть бесконечно: на горящий огонь, на текущую воду и на то, как у #python-истов горит с
match
.Хабр
Немного примеров match/case в Python 3.10
Не так давно (а именно 4 октября 2021 года) официально увидела свет юбилейная версия языка python, а именно версия 3.10. В ней было добавлено несколько изменений, а самым интересным (на мой взгляд)...
#prog
Интервью от 2004 года с Julian Seward, создателем Valgrind. Не смотря на возраст материала, читать интересно.
Некоторые интересные моменты:
* В отличие от приличного количества инструментов из мира UNIX, Valgrind был создан в 21 веке (первая версия вышла в 2002 году)
* "One of the major parts of GHC I worked on was the back-end x86 and SPARC code generators, and the register allocator. From this I learnt a lot about the x86 instruction set and code generation techniques, and the idea of making a memory-checking tool for Linux came back into view."
* Вопреки расхожему мнению, название Valgrind — не сокращение от "value grinder" или чего-то похожего, как можно было бы подумать, а взято из скандинавской мифологии (передаю привет Антону)
* "Valgrind is only useful because C and C++ are such crappy programming languages."
* "Valgrind is loaded with assertion checks and internal sanity checkers which periodically inspect critical data structures. These are permanently enabled. I don't care if 5 percent or even 10 percent of the total run-time is spent in these checks—automated debugging is the way to go. As a result, Valgrind almost never segfaults—instead it emits some kind of a useful error message before dying. That's something I'm rather proud of."
Интервью от 2004 года с Julian Seward, создателем Valgrind. Не смотря на возраст материала, читать интересно.
Некоторые интересные моменты:
* В отличие от приличного количества инструментов из мира UNIX, Valgrind был создан в 21 веке (первая версия вышла в 2002 году)
* "One of the major parts of GHC I worked on was the back-end x86 and SPARC code generators, and the register allocator. From this I learnt a lot about the x86 instruction set and code generation techniques, and the idea of making a memory-checking tool for Linux came back into view."
* Вопреки расхожему мнению, название Valgrind — не сокращение от "value grinder" или чего-то похожего, как можно было бы подумать, а взято из скандинавской мифологии (передаю привет Антону)
* "Valgrind is only useful because C and C++ are such crappy programming languages."
* "Valgrind is loaded with assertion checks and internal sanity checkers which periodically inspect critical data structures. These are permanently enabled. I don't care if 5 percent or even 10 percent of the total run-time is spent in these checks—automated debugging is the way to go. As a result, Valgrind almost never segfaults—instead it emits some kind of a useful error message before dying. That's something I'm rather proud of."
TechRepublic
Open Source Awards 2004: Julian Seward for Valgrind
For the Linux-on-Intel-x86 crowd, one of the most popular debugging options available is Julian Seward's Valgrind. This free program emulates the Intel CPU so that it can see exactly what your program is doing.
#prog #article #soc
В основе библиотек для PBT (property-based testing) лежит фреймворк для нахождения и минификации набора аргументов, на котором выполняется некоторый предикат. Этот фреймворк можно применять для совсем разных целей, например, для того, чтобы найти набор предпочтений избирателей, на которых разные методики выборов дадут разные показатели (да, это всё ещё блог hypothesis).
И да, альтернативы обычному большинству голосов есть. В этой статье с интерактивными визуализациями от Nicky Case рассказывается о пяти различных альтернативах и о их разных свойствах. Абсолютно лучшей среди них нету, но все они выгодно отличаются от простого большинства отсутствием эффекта спойлера (когда введение в списки голосований непопулярного кандидата, который, тем не менее, оттягивает на себя голоса, позволяет сменить исход выборов между двумя наиболее популярными кандидатами).
(Есть также русскоязычная адаптация (с сохранением и переводом интерактивных элементов), но это именно что адаптация, так что не могу безусловно рекомендовать)
В основе библиотек для PBT (property-based testing) лежит фреймворк для нахождения и минификации набора аргументов, на котором выполняется некоторый предикат. Этот фреймворк можно применять для совсем разных целей, например, для того, чтобы найти набор предпочтений избирателей, на которых разные методики выборов дадут разные показатели (да, это всё ещё блог hypothesis).
И да, альтернативы обычному большинству голосов есть. В этой статье с интерактивными визуализациями от Nicky Case рассказывается о пяти различных альтернативах и о их разных свойствах. Абсолютно лучшей среди них нету, но все они выгодно отличаются от простого большинства отсутствием эффекта спойлера (когда введение в списки голосований непопулярного кандидата, который, тем не менее, оттягивает на себя голоса, позволяет сменить исход выборов между двумя наиболее популярными кандидатами).
(Есть также русскоязычная адаптация (с сохранением и переводом интерактивных элементов), но это именно что адаптация, так что не могу безусловно рекомендовать)
hypothesis.works
Exploring Voting Systems with Hypothesis - Hypothesis
Exploring Voting Systems with Hypothesis Hypothesis is, of course, a library for writing tests.
But from an implementation point of view this is hardly noticeable.
Really it’s a library for constructing and exploring data and using it
to prove or disprove…
But from an implementation point of view this is hardly noticeable.
Really it’s a library for constructing and exploring data and using it
to prove or disprove…
Извините, но чуток #wafflecontext. Надеюсь, вы следите за новостями
Twitter
Aaron Patterson
It's not ✌️personal info✌️, it's just "Meta Data"!
Подписчики, дорогие мои, в довольно скором времени будет Rustcon. Мне туда хочется попасть (🧇), но идти просто слушателем не хочется а ещё меня жаба душит отдавать за билет 14 тысяч. Поэтому у меня есть хитрый план: взять один из своих авторских постов в Блог*е и переработать его в доклад. Так что у меня к вам вопрос: какой пост(ы), на ваш взгляд, заслуживает конвертации в доклад для конфы?
rustcon.ru
Конференция по языку программирования Rust, Москва, 28 ноября 2025
#prog #rust #моё
Как я уже рассказывал, гетерогенные списки (HList) бывают весьма удобными для различных выкрутасов на уровне типов. Сегодня я расскажу о том, как можно из отдельных компонент, реализующих поведение, диктуемое обобщённым типом, собрать HList, который будет выбирать нужную операцию в зависимости от типа — фактически, статический type dispatch. Для того, чтобы разговор был более конкретным, обозначим функционал, который мы будем пытаться совмещать:
Мы можем сделать разные трейты для
Проблема с наивным подходом состоит в том, что мы пытаемся реализовать один и тот же трейт двумя разными способами. А что, если мы вынесем источник, откуда взята реализация, в какой-то тип? В этом случае две реализации будут различаться путём до источника метода
Вводить этот путь при помощи ассоциированных типов — тупиковый вариант, потому что они не являются параметрами трейтов. Нам придётся поменять определение
Как я уже рассказывал, гетерогенные списки (HList) бывают весьма удобными для различных выкрутасов на уровне типов. Сегодня я расскажу о том, как можно из отдельных компонент, реализующих поведение, диктуемое обобщённым типом, собрать HList, который будет выбирать нужную операцию в зависимости от типа — фактически, статический type dispatch. Для того, чтобы разговор был более конкретным, обозначим функционал, который мы будем пытаться совмещать:
trait Provide<Item> {
fn provide(&mut self) -> Item;
}
И строительные блоки:struct HNil;
struct HCons<H, T>(H, T);
Первое, что приходит на ум — это реализация в лоб, т. е. реализовать трейт для HCons
в том случае, если его реализует либо голова, либо хвост:impl<Item, H, T> Provide<Item> for HCons<H, T>
where
H: Provide<Item>,
{
fn provide(&mut self) -> Item {
self.0.provide()
}
}
impl<Item, H, T> Provide<Item> for HCons<H, T>
where
T: Provide<Item>,
{
fn provide(&mut self) -> Item {
self.1.provide()
}
}
Даже без запуска понятно, что это не сработает: если и голова, и хвост реализуют Provide<Item>
, то у нас выходит две различные реализации для HCons
. И действительно, компилятор жалуется:error[E0119]: conflicting implementations of trait
Provide<_>
for type HCons<_, _>
Мы можем сделать разные трейты для
Provide
из головы и Provide
из хвоста и потом объединить их при помощи blanket impl, но мы опять упрёмся в перекрывающиеся реализации. Так что же делать?Проблема с наивным подходом состоит в том, что мы пытаемся реализовать один и тот же трейт двумя разными способами. А что, если мы вынесем источник, откуда взята реализация, в какой-то тип? В этом случае две реализации будут различаться путём до источника метода
provide
, а потому формально это будут два разных трейта (точнее, один, параметризованный двумя разными наборами тИповых аргументов). Явно этот путь нам прописывать не нужно, за нас его напишет вывод типов.Вводить этот путь при помощи ассоциированных типов — тупиковый вариант, потому что они не являются параметрами трейтов. Нам придётся поменять определение
Provide
и внести в него ещё один тИповой параметр:trait Provide<Item, Path> {
fn provide(&mut self) -> Item;
}
И, конечно, добавить типовые маркеры, отвечающие за компоненты пути:struct Itself;
struct Head<T>(T);
struct Tail<T>(T);
Теперь модифицируем реализации для Hcons
:impl<Item, H, T, HSource> Provide<Item, Head<HSource>> for HCons<H, T>
where
H: Provide<Item, HSource>,
{
fn provide(&mut self) -> Item {
self.0.provide()
}
}
impl<Item, H, T, TSource> Provide<Item, Tail<TSource>> for HCons<H, T>
where
T: Provide<Item, TSource>,
{
fn provide(&mut self) -> Item {
self.1.provide()
}
}
И... Оно компилируется. Что ж, сделаем пример:struct Cloning<T>(T);
impl<T> Provide<T, Itself> for Cloning<T>
where
T: Clone,
{
fn provide(&mut self) -> T {
self.0.clone()
}
}
fn _test() {
let mut list = HCons(Cloning(0), HCons(Cloning(()), HNil));
let _: u32 = list.provide();
let _: () = list.provide();
}
Как видите, всё прекрасно работает, нужные типы выводятся по возвращаемому результату. Сила вывода типа!Telegram
Блог*
#prog #rust #моё
Допустим, нам нужно проанализировать большой JSON, и нам нужно вытащить часть полей с конкретными типами, но по возможности оставить остальные. При этом этот наборы полей в разных местах немного разные, так что повторять себя не хочется.…
Допустим, нам нужно проанализировать большой JSON, и нам нужно вытащить часть полей с конкретными типами, но по возможности оставить остальные. При этом этот наборы полей в разных местах немного разные, так что повторять себя не хочется.…
Окей, а что будет, если в списке окажется два типа, которые могут предоставлять требуемый тип, или, наоборот, не будет ни одного? Проверим:
--> src/lib.rs:47:23
|
47 | let _: u32 = list.provide();
| ^^^^^^^ the trait
Что ж, вполне логичный ответ. А теперь для конфликтующих провайдеров:
Что ж, ошибка явно могла бы быть более внятной, но, по крайней мере, она есть.
Так что, мы закончили? Не совсем. Есть парочка вещей, которые мне не нравятся.
Во-первых, тем, кто это использует, придётся реализовывать
В-третьих, если типчики всё-таки не сходятся, исправлять неоднозначность приходится при помощи полностью квалифицированного вызова, что неудобно. Решается добавлением extension trait с методом, который предоставляет возможность прокинуть нужный тип:
let mut list = HCons(Cloning(()), HCons(Cloning(()), HNil));
let _: u32 = list.provide();
Ответ компилятора:error[E0277]: the trait bound
HCons<Cloning<()>, HCons<Cloning<()>, HNil>>: Provide<u32, _>
is not satisfied--> src/lib.rs:47:23
|
47 | let _: u32 = list.provide();
| ^^^^^^^ the trait
Provide<u32, _>
is not implemented for HCons<Cloning<()>, HCons<Cloning<()>, HNil>>
Что ж, вполне логичный ответ. А теперь для конфликтующих провайдеров:
let mut list = HCons(Cloning(()), HCons(Cloning(()), HNil));
let _: () = list.provide();
Ответ компилятора:error[E0282]: type annotations needed
--> src/lib.rs:47:23
|
47 | let _: () = list.provide();
| ^^^^^^^ cannot infer type for type parameter
Path
declared on the trait Provide
Что ж, ошибка явно могла бы быть более внятной, но, по крайней мере, она есть.
Так что, мы закончили? Не совсем. Есть парочка вещей, которые мне не нравятся.
Во-первых, тем, кто это использует, придётся реализовывать
Provide<Item, Itself>
для своих типов, ибо навряд ли они такие же обобщённые. Несколько бойлерплейтно. Обходится созданием отдельного трейта, который будет реализовывать Provide<_, Itself>
через blanket impl:trait ProvideBase<Item> {
fn provide_base(&mut self) -> Item;
}
impl<Item, T> Provide<Item, Itself> for T
where
T: ProvideBase<Item>,
{
fn provide(&mut self) -> Item {
self.provide_base()
}
}
Во-вторых, при реализации Provide
можно использовать произвольные типы для путей, что позволяет немного сломать код:impl Provide<u32, Head<Itself>> for HCons<(), HNil> {
fn provide(&mut self) -> u32 {
0
}
}
// где-то в коде
let _: u32 = HCons(Cloning(42u32), HCons((), HNil)).provide();
// ^~~ error: type annotations needed
Это было бы неприятным, если бы мы строили вокруг этого библиотеку, даром, что ломается пользовательский код. Оградиться от этого, теме не менее, достаточно просто: сделаем sealed trait для типов-компонент путей, повесим в качестве ограничения на тип Path
в определении Provide
, и реализуем для Head
, Tale
и Itself
, но Itself
оставим единственным публичным типом.В-третьих, если типчики всё-таки не сходятся, исправлять неоднозначность приходится при помощи полностью квалифицированного вызова, что неудобно. Решается добавлением extension trait с методом, который предоставляет возможность прокинуть нужный тип:
trait ProvideExt<T> {
fn provide_via_path<P>(&mut self) -> T
where
Self: Provide<T, P>;
}
impl<Item, T> ProvideExt<Item> for T {
fn provide_via_path<P>(&mut self) -> Item
where
Self: Provide<Item, P>,
{
self.provide()
}
}
Ну и прежде чем закончить, хочу отметить, что решение с путями на уровне типов я придумал не на пустом месте, а вдохновившись вот этим постом Дэдфуда. Вот и всё, как всегда, весь код в гисте.rust-lang.github.io
Future proofing - Rust API Guidelines
This is a set of recommendations on how to design and present APIs for the Rust programming language.