Forwarded from мне не нравится реальность (waffle 🧇🍓)
NerdyPepper/eva
Простой REPL калькулятор с историей и подсветкой синтаксиса. На расте.
Простой REPL калькулятор с историей и подсветкой синтаксиса. На расте.
мне не нравится реальность
Зачем вести блог, если можно просто репостить Блог*?
Зачем вести Блог*, если можно просто репостить Вафлю?
Forwarded from dd if=/dev/stuff of=/dev/tg
Павел Дуров поделился 7 секретами вечной молодости:
1. Наличие однопараметрического типа Т
2. Наличие аппликативного функтора для типа Т
3. Наличие функции
4. Наличие функций
5. Закон левой идентичности
6. Закон правой идентичности
7. Закон ассоциативности
1. Наличие однопараметрического типа Т
2. Наличие аппликативного функтора для типа Т
3. Наличие функции
return
4. Наличие функций
join
или bind
5. Закон левой идентичности
6. Закон правой идентичности
7. Закон ассоциативности
#prog #rust #rustlib
"semeion is a small Rust library that allows you to write simulations that run in a 2D (torus) environment, well suited for cellular automata simulations or zero-player games."
А также небольшой пост о библиотеке.
"semeion is a small Rust library that allows you to write simulations that run in a 2D (torus) environment, well suited for cellular automata simulations or zero-player games."
А также небольшой пост о библиотеке.
GitHub
GitHub - gliderkite/semeion: A 2D environment simulator, that let's you define the behavior and the shape of your entities, while…
A 2D environment simulator, that let's you define the behavior and the shape of your entities, while taking care of dispatching events generation after generation. - GitHub - gliderkite/sem...
#prog #c #article #abnormalprogramming
Опус товарища @HirrolotThinks о метапрограммировании на сишных макросах.
Опус товарища @HirrolotThinks о метапрограммировании на сишных макросах.
Хабр
Металингвистический совратитель Си. Опус I: Предварительные ласки
>> Осторожно, модерн! 2 — 0.1. Спор на баксы и девчонок Предисловие Система макросов добавлена в язык программирования Си с целью абстрагирования часто повторяю...
Ёлки-палки, я вроде бекендер, почему я сейчас гуглю по работе, можно ли использовать
--
внутри тегов комментариев HTML?🤔1
Forwarded from Vlad Beskrovnyi
Из-за отсутствия внятной спецификации, в расте то и дело возникают вопросы "'это баг или фича?". И когда все-таки решат, что баг, может выясниться, что он уже всеми повсюду используется, как фича. И вроде и людей в этом не обвинишь, ведь нигде не написано, что это баг - ведь ланг дезигнеры и сами внятно сказать не могли, баг или не баг! Приходится что-то выкостыливать. Вот напр я репортил - https://github.com/rust-lang/rust/issues/74556
Тут сначала не могли понять, баг или не баг. Потом все же решили, что баг. Потом выяснили, что он уже есть в нескольких стабильных релизах. Потом исправили, но выяснили, что кто-то баг уже использует, так что на новой найтли что-то перестало компилиться. Вроде решили, что и фиг с ним
Тут сначала не могли понять, баг или не баг. Потом все же решили, что баг. Потом выяснили, что он уже есть в нескольких стабильных релизах. Потом исправили, но выяснили, что кто-то баг уже использует, так что на новой найтли что-то перестало компилиться. Вроде решили, что и фиг с ним
GitHub
Glob Time Travel · Issue #74556 · rust-lang/rust
I tried this code: mod foo { pub mod bar { pub mod bar { pub fn foobar() {} } } } use foo::*; use bar::bar; use bar::foobar; fn main() { bar::foobar(); } I expected to see this happen: Compilation ...
#prog #computergraphics
Статья (перевод) о попытке сделать рендеринг поверх не чисел с плавающей точкой, а поверх рациональных чисел. Спойлер: для получения приемлемых результатов автору пришлось реализовать арифметику с "плавающей дробной чертой"
Статья (перевод) о попытке сделать рендеринг поверх не чисел с плавающей точкой, а поверх рациональных чисел. Спойлер: для получения приемлемых результатов автору пришлось реализовать арифметику с "плавающей дробной чертой"
iquilezles.org
Inigo Quilez
Articles on computer graphics, math and art
Forwarded from oleg_log (Oleg Kovalov)
Collection of articles on good practices and tools to improve C code quality
Интересно тем, что от автора LZ4 и ZSTD (можно сказать лучшие компрессоры данных, да, на Си)
https://github.com/Cyan4973/Writing_Safer_C_code
Интересно тем, что от автора LZ4 и ZSTD (можно сказать лучшие компрессоры данных, да, на Си)
https://github.com/Cyan4973/Writing_Safer_C_code
GitHub
GitHub - Cyan4973/Writing_Safer_C_code: Collection of articles on good practices and tools to improve C code quality
Collection of articles on good practices and tools to improve C code quality - Cyan4973/Writing_Safer_C_code
#prog #rust #моё
Рассмотрим следующий код на Rust:
Окей, признаю, я вас немного обдурил, вся фишка кроется в коде, который я не показал. Разумеется, я его покажу, а попутно затрону две темы в Rust: deref coercion и interiour mutability.
Но сначала давайте поговорим о слайсах. Они достаточно удобны. Их можно индексировать и снова получать слайсы. Для них определено множество полезных методов: сортировка, поворот, обращения порядка, линейный и бинарный поиски... Однако, все эти методы можно также вызвать и на массивах, и на
Давайте посмотрим на метод Vec::sort. Этот метод описан в блоке "Methods from
Ладно, это было поучительно, но какое оно имеет отношение к безобразию, показанному в начале? Дело в том, что одна из (почему-то малоизвестных) ситуаций, когда методы этих трейтов могут вызваны — это... Доступ к полю. Если в коде есть
Рассмотрим следующий код на Rust:
// код опущен для краткостиОчевидно, этот код не работает. И действительно, если мы запустим эту программу, то один из ассертов запустит панику. В данном случае это будет... Будет... Погодите-ка, оно работает? Что?! Но ведь в Rust нет свойств!
fn main() {
let tricky = <Tricky as Default>::default();
assert_eq!(tricky.field, 7);
assert_eq!(tricky.field, 4);
assert_eq!(tricky.field, 13);
let mut nice_try = <NiceTry as Default>::default();
assert_eq!(nice_try.field, 0);
nice_try.field += 12;
assert_eq!(nice_try.field, 0);
let (mut a, mut b) = <(Unstable, Unstable) as Default>::default();
assert_eq!((a.field, b.field), (0, 0));
std::mem::swap(&mut a.field, &mut b.field);
assert_eq!((a.field, b.field), (10, 10));
}
Окей, признаю, я вас немного обдурил, вся фишка кроется в коде, который я не показал. Разумеется, я его покажу, а попутно затрону две темы в Rust: deref coercion и interiour mutability.
Но сначала давайте поговорим о слайсах. Они достаточно удобны. Их можно индексировать и снова получать слайсы. Для них определено множество полезных методов: сортировка, поворот, обращения порядка, линейный и бинарный поиски... Однако, все эти методы можно также вызвать и на массивах, и на
Vec
. Как это работает? Неужели реализация этих методов скопирована с методов для слайсов? Конечно, нет.Давайте посмотрим на метод Vec::sort. Этот метод описан в блоке "Methods from
Deref<Target = [T]>
". Что это означает? В стандартной библиотеке Rust (на самом деле core) есть трейт Deref, описанный следующим образом:trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
Как нетрудно видеть, он позволяет получить из ссылки на значение одного типа ссылку на значение другого типа. У этого трейта есть дополняющий его DerefMut, который выполняет преобразование между мутабельными ссылками:trait DerefMut: Deref {
fn deref_mut(&mut self) -> &mut Self::Target;
}
Возникает закономерный вопрос: а чем они отличается от AsRef и AsMut, которые также выполняют преобразования между ссылками? Ну, во-первых, в силу того, что целевой тип преобразования у Deref
и DerefMut
является ассоциированным типом, а не обобщённым параметром, у любого типа может быть не более одной реализации Deref
и DerefMut
. А во-вторых — и это уже куда как более существенное отличие — это один из "магических" (известных компилятору) трейтов, методы которого часто вызываются неявно. Конкретно методы Deref{, Mut}
вызываются для кастомных реализаций операторов разыменовывания, а также ещё неявно в некоторых контекстах, в частности, при вызове методов через точку. Это, в том числе, позволяет эргономично пользоваться умными указателями. Если на минуту забыть о том, что Vec
может менять свою длину, мы можем считать его ссылкой на лежащий в куче массив с длиной, известной лишь на этапе исполнения. То есть... Указатель на слайс. И действительно, Vec
реализует Deref{, Mut}<Target = [T]>
, что позволяет вызывать на нём методы, определённые для слайса. И при этом без каких-либо дополнительных телодвижений с вызывающей стороны!Ладно, это было поучительно, но какое оно имеет отношение к безобразию, показанному в начале? Дело в том, что одна из (почему-то малоизвестных) ситуаций, когда методы этих трейтов могут вызваны — это... Доступ к полю. Если в коде есть
foo.field
и foo
имеет тип Foo
, у которого нету поля field
, но Foo
реализует Deref<Target = Bar>
, где у типа Bar
есть поле field
, то такое обращение к полю будет корректно и будет вызывать deref
(или deref_mut
). Все те странные структуры, которые я показал, так или иначе оборачивают структуру Simple
:#[derive(Default)]
struct Simple {
field: u32,
}
Wikipedia
Property (programming)
type of class member in object-oriented programming which is accessed like a field but implemented as subroutine(s)
Давайте сначала разберём
Тот же анализ заимствований, который компилятор Rust делает на этапе компиляции, можно делать во время исполнения. Именно этот паттерн и реализует RefCell. Этот тип подсчитывает количествоссылок доступов к данным во время исполнения и паникует, если в какой-то момент должны возникнуть одновременно изменяемый доступ и хоть сколько-то неизменяемых — или более одного изменяемого. На проблему гонок данных также можно взглянуть с другого конца. Гонка данных считается неопределённым поведением, поскольку для многих типов данных операция обновления не является атомарной, т. е. неделимой. Если два ядра будут менять значение одновременно, то это может привести к тому, что промежуточные операции обновления будут чередоваться друг с другом и привести к тому, что в памяти значение окажется в неожиданном состоянии — неожиданное для того, кто писал код в расчёте на атомарность изменений (на самом деле тут есть ещё более сложные противные вещи, связанные с кешами процессоров, но сегодня я не хочу в это углубляться). Однако для простых значений, умещающихся в одно машинное слово, процессор на самом деле может гарантировать атомарность изменений. Тогда, если два ядра одновременно изменяют атомарное значение, оба этих изменения будут учтены. В таком случае гонка данных просто не может причинить вред, а значит, атомарные значения вполне можно отдавать по разделяемым (
NiceTry
. Вот её определение:#[derive(Default)]У нас есть два поля одного типа. Как же работает трюк с подменой? Очень просто: в
struct NiceTry {
first: Simple,
second: Simple,
}
Deref::deref
мы возвращаем ссылку на одно поле, а в DerefMut::deref_mut
— на другое:impl Deref for NiceTry {
type Target = Simple;
fn deref(&self) -> &Self::Target {
&self.first
}
}
impl DerefMut for NiceTry {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.second
}
}
Неудивительно, что мы не могли поменять field
— мы не могли получить к нему мутабельный доступ!Unstable
устроен несколько сложнее. Если у нас есть мутабельный доступ к полю внутри метода, то мы можем его... Мутировать. То есть поменять. Собственно, именно это и происходит в реализации deref_mut
:#[derive(Default)]
struct Unstable(Simple);
impl Deref for Unstable {
type Target = Simple;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Unstable {
fn deref_mut(&mut self) -> &mut Self::Target {
self.0.field += 10;
&mut self.0
}
}
"Ладно" — может сказать кто-то из моих читателей — "я понимаю, как работает трюк с NiceTry и Unstable, но что, чёрт побери, происходит с Tricky? Мы ведь даже не используем мутабельный доступ к Tricky, так что мы не можем что-то там поменять!". Что ж, мой недоумённый читатель (а также другие), я вынужден раскрыть одну из самых грязных тайн Rust: &mut T
на самом деле не означает "изменяемая ссылка"! Что же это тогда? Фактически, &mut T
означает уникальную ссылку на значение типа T
— то есть такую, что в любой момент времени одновременно с этой ссылкой не существует никаких других. Почему это так важно? Дело, что одна из вещей, которая является в Rust неопределённым поведением — это гонка данных, ситуация, когда доступ к одному и тому же значению происходит из двух (или более) разных мест одновременно, и при этом как минимум один доступ — на запись. Простейший (концептуально, разумеется) доступ добиться отсутствия гонок данных — это убедиться, что в любой момент времени только кто-то один имеет изменяемый доступ к данным. Это именно то, что компилятор Rust проверяет, используя концепции владения и заимствования. Но это не единственный способ!Тот же анализ заимствований, который компилятор Rust делает на этапе компиляции, можно делать во время исполнения. Именно этот паттерн и реализует RefCell. Этот тип подсчитывает количество
&
) ссылкам. И действительно, если мы откроем документацию к, скажем, AtomicU32, то мы увидим, что практически все методы принимают &self
.Wikipedia
Race condition
situation in computer system that occurs when multiple processes try to access a common resource