Size: a a a

2020 September 04
Блог*
#prog #rust

Разбор библиотеки для автоматизации конверсии Cell<Struct> -> Cell<Field>.

abubalay.com/blog/2020/01/05/cell-field-projection
источник
Блог*
Вызывающий прения #prog #meme
источник
Блог*
источник
Блог*
#prog #rust #article

Я считаю, что в дизайне современных языков программирования упущена весьма важная тема: перекрывающийся доступ к значениям (aliasing). В статье Niko Matsakis (старой, написанной ещё в те времена, когда в Rust ещё был сборщик мусора) раскрывается связь между управлением памятью и отсутствием гонок данных. В статье Manish Goregaokar эта тема раскрыто несколько более глубоко, а в статье Matt Brubeck рассказывается, в частности, о том, как связаны мутабельность и уникальность доступа и как можно построить безопасные API поверх небезопасного, предоставляющего безусловное перекрытие доступа.

И да, если вы считаете, что это исключительно бзик Rust, то вот вам статьи о аналогичных механизмах в Swift и D.
источник
Блог*
#prog #rust #моё

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

Я задумался над тем, как можно упростить подобное решение, не потеряв эффективности мутабельных изменений, и, кажется, нашёл тот краеугольный камень, с помощью которого можно выстроить такую инфраструктуру, подобно тому, как все методы Iterator определены через Iterator::next. Это трейт Apply:

trait Apply {
   type Patch;
   fn apply(&mut self, patch: Self::Patch) -> Self::Patch;
}


Дополнительное требование к реализации, которое, увы, невыразимо в коде на Rust (но было бы выразимо на, скажем, Agda или Idris), состоит в том, что изменение, возвращённое apply, будучи применённым обратно к self, переводит его в первоначальное состояние (до степени, требуемой задачей: это изменение может поменять, скажем, ёмкость хэшмапы, но навряд ли для вас это существенно). Иными словами,

let changed = {
   let mut changed = original.clone();
   let undo = changed.apply(change);
   changed.apply(undo);
   changed
};
assert_eq!(original, changed);


Данное определение вкупе с приведённым выше требованием обеспечивает композируемость и, как следствие, линейную историю. Скажем,

let undo1 = state.apply(change1);
let undo2 = state.apply(change2);
let undo3 = state.apply(change3);
state.apply(undo3);
state.apply(undo2);
state.apply(undo1); // сейчас state находится в том же
                   // состоянии, что и до начала преобразований

Разумеется, хранить историю можно и в более организованном виде. Скажем, вот как организовывается обобщённая структура для поддержки отмены изменений:

struct Undo<Data: Apply> {
   data: Data,
   changes: Vec<Data::Patch>,
}

impl<Data: Apply> Undo {
   fn get(&self) -> &Data {
       &self.data
   }
   fn apply(&mut self, patch: Data::Patch) {
       self.changes.push(self.data.apply(patch));
   }
   fn undo(&mut self) {
       if let Some(undo) = self.changes.pop() {
           self.data.apply(undo);
       }
   }
}


Если несколько изменить способ хранений изменений и не отбрасывать их, то можно также реализовать redo.

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

struct Patching<Data>(Data);
struct Unapply<'a, Data: Apply> {
   data: &'a mut Data,
   undo: Option<Data::Patch>,
}

impl<Data: Apply> Patching<Data> {
   fn applying(&mut self, patch: Data::Patch) -> Unapply<Data> {
       let undo = self.0.apply(patch);
       Unapply {
           data: &mut self.0,
           undo: Some(undo),
       }
   }
}

impl<Data: Apply> Unapply<'_, Data> {
   fn applying<'a>(&'a mut self, patch: Data::Patch) -> Unapply<'a, Data> {
       let undo = self.data.apply(patch);
       Unapply {
           data: &mut self.data,
           undo: Some(undo),
       }
   }
}

impl<Data: Apply> Drop for Unapply<'_, Data> {
   fn drop(&mut self) {
       let undo = self.undo.take().unwrap();
       self.data.apply(undo);
   }
}


Этот метод уже по эргономике приближается к варианту с персистентными структурами данных: если мы в каждый момент времени работаем только с одной версией структуры, то этого достаточно, при этом нам не требуется применять отмену руками, всё происходит автоматически.
источник
Блог*
По идее, здесь должен был быть мотивирующий пример, показывающий, как вся эта машинерия упрощает код, и я думал о том, чтобы сделать решатель судоку... А потом понял, что набор всех возможных значений для всех 9 ⨯ 9 = 81 клеток поля занимает настолько мало места, что его проще копировать целиком, чем содержать целый список изменений (либо в куче, либо неявно на стеке, как в случае с Unapply), так что у меня пропала мотивация делать этот относительно сложный пример. Может, вы сможете что-то подсказать?
источник
2020 September 05
Блог*
#prog #rust #article

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

В этой статье рассказывается о консервативном расширении PEG, добавляющем семантику восстановления после ошибки разбора. Чуда не случилось в том смысле, что много чего надо писать руками, но авторам удалось побить ANTLR — как по качеству сообщений об ошибках, так и по быстроте работы.
А вот также статья, адаптирующая этот подход к парсер-комбинаторам (конкретно к nom)
источник
2020 September 06
Блог*
SFINAE надо было назвать SNAFU
источник
Блог*
Если вам было мало вот этого всего в 2020

https://twitter.com/patriceroy1/status/1302055575140945921
источник
2020 September 07
Блог*
#prog #rust #article

Как заставить программы на Rust работать с длинными путями на Windows.

gal.hagever.com/posts/windows-long-paths-in-rust/
источник
Блог*
#prog #rust #successstory

"What would our ideal language look like for rewriting our LIQUID platform? Since a key feature of LIQUID is its speed and low latency, performance and the lack of a garbage collector were an absolute must. We also needed broad cross-platform support, as we want to run LIQUID everywhere, from iOS, Android, Mac, Windows, Linux, and even embedded devices. This hypothetical language would need C interoperability with no performance overhead so that we could integrate with existing components and dip into raw memory access when performance demanded it. Ideally, this language would also be safer than C/C++, helping us to prevent common programming errors at compile time. It turns out there is a language that does all that and more…"

astropad.com/why-rust/
источник
Блог*
#prog #rust #successstory

"With all of the optimizations, you’d expect Condure to run pretty well. Early observations confirm this to be true! We’ll publish more detailed benchmarks in the future, but here are some standout points:

  * We were able to establish 1 million client connections to a single instance.
  * We load tested ~16k HTTP requests/second using a single ZeroMQ handler.
  * We are seeing a 90% reduction in CPU usage compared to Mongrel2 on our production systems."

blog.fanout.io/2020/08/11/rewriting-pushpins-connection-manager-in-rust/
источник
Блог*
#prog #article

Разбор довольно старой статьи с описанием различных схем реализации структур данных, хранящих большое количество таймеров. Спойлер: иерархичность рулит! Причём не только с таймерами, но и с аллокациями и битовыми множествами.
источник
Блог*
#web

Инструмент для перевода сайтов на WordPress в статические в один клик.

https://www.strattic.com
источник
Блог*
Это просто АААААААААААААААААААААААААААААААА
(а ещё #prog #meme, но это не важно)
источник
Блог*
источник
Блог*
#prog #cpp #article

Ссылки в C++ — это очень просто.

herbsutter.com/2020/02/23/references-simply/
источник
2020 September 08
Блог*
Один банк офигительней другого
источник
Блог*
При покупках картой Альфа не проверяет CVV-код. @banksta
источник
Блог*
#article

Фраза "рабочие ритуалы" приобретает пугающе буквальный оттенок.

Оригинал
Перевод на Хабре
источник