1.83K subscribers
3.3K photos
132 videos
15 files
3.58K links
Блог со звёздочкой.

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

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
Помните scoped threads из crossbeam, которые позволяют спавнить не 'static функции (замыкания, которые захватывают что-то по ссылке)?

В std скоро() собираются такое добавить: <twitter:m_ou_se>
#prog #cpp #abnormalprogramming

twitter.com/sehetw/status/1465726704979267586

Вообще это было переслано в <twitter:Affective C++>, но прикольно, что на C++ можно до некоторой степени сымитировать именованные прерывания цикла
#prog #cpp #article

shared_ptr<T>: the (not always) atomic reference counted smart pointer

Статья о том, как shared_ptr может использовать не атомарные инкременты (и некоторые спекуляции на тему того, является ли это вообще безопасным)
Forwarded from Alex Gualse's posts
A lot of fonts show letter I and l very similar and it's wrong.

If you somewhere use any fonts, take care about they have different I and l especially where there is user input (like about yourself, post texts, etc)
#article

Статья (перевод) от основателя Signal с впечатлениями от так называемого web3.

TL;DR: реалии этих проектов противоречат декларируемым ценностям (главным образом децентрализации) и вообще катастрофически сломаны.
Какой ваш любимый язык программирования и почему это Rust?
Channel photo updated
В свежем Rust 1.58.0 наконец-то можно использовать переменные напрямую при форматировании строк:

let person = get_person();
// ...
println!("Hello, {person}!"); // captures the local `person`

Пока что это работает только с именами, а не произвольными выражениями, но всё равно приятно. Прощайте format!("{name}", name = name);!
Ещё из плющек:
— теперь *const T указатели можно дерефать в константных контекстах
— Теперь правила ансайзинга для дженерик структур немного проще[1]
— В copy{,_nonoverlapping} опять включили debug_assert'ы[2]
— реализация Clone для RSplit<T, P> больше не требует T: Clone
— Трейт Termiation теперь реализов для Result<Infallible, E>, позволяя писать fn main() -> Result<Infallible, ErrorType>, для програм которые не заканчиваются успешно через выход из main
— Стабилизировали File::options, замену FileOptions::new
— Стабилизировали {Option,Result}::unwrap_unchecked
— Стабилизировали многие методы Duration и MaybeUninit как const fn
— Компилятор теперь будет пытаться применять стабильные методы прежде, чем не стабильные. Это позволит избежать поломок при добавлении в std
методов, пересикающихся по именам с методами из сторонних трейтов.
rustdoc теперь показывает методы из всех Deref реализаций, рекурсивно (а не только из первой)

[1]: Новые правила позволяют такое:
struct A<T, U: ?Sized + 'static>(T, B<T, U>);
struct B<T, U: ?Sized>(T, U);

fn main() {
let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
// This previously did not work as the last field of `A` also mentions `T`,
// as only `U` changes this is now allowed thanks to this feature.
let _y: &A<[u32; 1], [u32]> = &x;
}

TL;DR: если последнее поле это структура, которая ансайзиться, то теперь и наружняя структура тоже ансайзиться.

А полные новые правила такие:
— the tail field depends on at least one type or const parameter not used in any other field
— the target struct can be created from the source by replacing only the parameters only found in the last struct field
— the tail field implements Unsize from source to target

[2]: Ранее они были отключены из-за того, что их нельзя выполнить в const fn

Полный список изменений: RELEASES.md#version-1580-2022-01-13
#prog #rust

Хозяйке на заметку

Как известно, если у типа в Rust есть несколько методов от разных трейтов с одними и теми же именами, то попытка вызвать один из них при помощи синтаксиса метода будет прервана компилятором с жалобой на неоднозначность имён, вынуждая прибегнуть к развёрнутому синтаксису вызова (Trait::method(&value, arg1, arg2)). Менее известен тот факт, что методы самого типа (inherent methods) перекрывают одноимённые методы трейтов, так что если одному имени отвечают метод типа и сколько угодно методов трейтов, то предпочтение всегда отдаётся методу самого типа и не вызывает неоднозначностей. Этим можно воспользоваться, чтобы иметь возможность в необобщённом контексте вызывать методы трейта, не импортируя сам трейт:

trait Trait {
fn method(&mut self, arg: Arg);
}

struct Type {
...
}

impl Trait for Type {
fn method(&mut self, arg: Arg) {
...
}
}

impl Type {
fn method(&mut self, arg: Arg) {
Trait::method(self, arg)
}
}

// где-то в другом месте, где в текущем пространстве имён
// есть Type, но нету Trait:

let mut value = Type::make(...);
value.method(arg);
🔥1
#prog #rust #моё

Допустим, нам нужно сделать на Rust бинарное дерево. Казалось бы, плёвое дело:

struct TreeNode<T> {
value: T,
left: Option<Box<Self>>,
right: Option<Box<Self>>,
}

struct Tree<T> {
root: Option<TreeNode<T>>,
}

Однако тут у нас по аллокации на каждый узел, от чего у нас страдает локальность данных и, как следствие, эффективность кеша (не говоря уже о стоимости аллокаций в рантайме). С другой стороны, у нас есть возможность делать дерево произвольной (насколько хватит оперативки, конечно же) высоты. А можем ли мы, отказавшись от произвольной высоты и задавая её предел наперёд, хранить вложенные узлы напрямую, а не через указатель? Как оказалось, да!

Но для начала немного о том, как мы будем задавать высоту. Так как решение на const generics потребует специализации и более продвинутой их обработки и потому абсолютно не реализуемо на стабильной версии, воспользуемся для задания высоты числами Пеано (да, я об этом уже писал):

struct Z;
struct S<T>(T);

Теперь немного подумаем о том, как это отобразить на древовидную структуру. Каждый узел дерева высотой N + 1 включает в себя узлы высотой N. Узел же дерева с высотой 0 не должен включать в себя данные вообще. Этого можно добиться, сопоставив Z тип с полями ненаселённого типа.

Кажется, что это изложение довольно легко перекладывается на код: определяем трейт с ассоциированным типом, который уменьшает число на единицу, реализуем его для S<T> с типом T, а для Z с типом never Infallible, параметризуем узел высотой Height и параметризуем вложенные узлы <Height as Decrement>::Output... К сожалению, это не работает: если определить узел таки образом, rustc не понимает, что рекурсия рано или поздно кончается, и жалуется на бесконечную вложенность типа без индирекции. Кажется, нам нужен другой подход.

С другой стороны, так уж сильно нам его менять не придётся: вместо того, чтобы отображать каждое число на число на единицу меньше, вы воспользуемся структурной индукцией и будем отображать число непосредственно на тип узла:

struct Node<T, Next> {
value: T,
left: Next,
right: Next,
}

Тут важно, что поля left и right имеют тип Next, а не Option<Next>, иначе мы не сможем сделать узел нулевой высоты ненаселённым типом. Собственно, вот как отображение выглядит для Z:

use std::convert::Infallible as Never;

trait Project<T> {
type Projected;
}

impl<T> Project<T> for Z {
type Projected = Node<T, Never>;
}

Итого узел нулевой высоты нельзя сконструировать, как мы и хотели. Лишь немногим сложнее выглядит отображение для S<N>:

impl<T, N> Project<T> for S<N>
where
N: Project<T>,
{
type Projected = Node<T, Option<N::Projected>>;
}

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

struct Tree<T, Height: Project<T>> {
repr: Height::Projected,
}

Теперь реализуем парочку вспомогательных методов и попробуем сделать дерево высоты 2 (=S<S<Z>>):

let tree: Tree<i32, S<S<Z>>> = Node {
value: 42,
left: None,
right: Some(Node {
value: 42,
left: None,
right: None
}),
}.into();

Что ж... Оно работает. И даже нормально печатается поле repr, если добавить #[derive(Debug)] на Node. Попробуем теперь поменять тип дерева на дерево с единичной высотой:

let tree: Tree<i32, S<Z>> = Node {
...

Компилятор ожидаемо жалуется:

error[E0271]: type mismatch resolving <Z as Project<i32>>::Projected == Node<{integer}, Option<_>>
--> src/main.rs:181:7
|
181 | }.into();
| ^^^^ expected enum Option, found enum Infallible
|
= note: expected struct Node<{integer}, Option<_>>
found struct Node<i32, Infallible>

Не слишком внятно, но цели статически ограничить высоту дерева мы успешно достигли.

Как всегда, весь код в гисте. И на этот раз даже больше, чем в посте: добавлены методы для поиска по дереву (с допущением, что дерево является двоичным деревом поиска) и немного более приятная печать.

Оставайтесь на связи. 🤙
Forwarded from Санечка Ъысь (Anna Weiss)