Блог*
#моё #prog #rust В крейте time есть структура Date с методом format, который возвращает String со датой, отформатированной согласно переданному формату. Выглядит это примерно так (пример из документации): assert_eq!(date!(2019-01-02).format("%Y-%m-%d"),…
#prog #rust #article
Аналогичный подход для создания аналога println/printf с проверками во время компиляции.
willcrichton.net/notes/type-safe-printf/
Аналогичный подход для создания аналога println/printf с проверками во время компиляции.
willcrichton.net/notes/type-safe-printf/
willcrichton.net
Implementing a Type-safe printf in Rust | Will Crichton
I show how to use heterogeneous lists and traits to implement a type-safe printf in Rust. These mechanisms can ensure that two variadic argument lists share important properties, like the number of format string holes matches the number of printf arguments.
#prog #rust #embedded #rustlib #amazingopensource
Исторически одной из проблем на пути использования Rust в встраиваемых устройствах был тот факт, что стандартная машинерия для форматирования сильно раздувает размер результирующего бинарника. Это особенно неприятно в силу того, что стандартная паника использует эту машинерию. Библиотека defmt от Ferrous System нацелена на решение это проблемы: она позволяет использовать форматирование (в том числе отложенное) и паники, сохраняя при этом маленький размер бинарника.
Исторически одной из проблем на пути использования Rust в встраиваемых устройствах был тот факт, что стандартная машинерия для форматирования сильно раздувает размер результирующего бинарника. Это особенно неприятно в силу того, что стандартная паника использует эту машинерию. Библиотека defmt от Ferrous System нацелена на решение это проблемы: она позволяет использовать форматирование (в том числе отложенное) и паники, сохраняя при этом маленький размер бинарника.
GitHub
GitHub - knurling-rs/defmt: Efficient, deferred formatting for logging on embedded systems
Efficient, deferred formatting for logging on embedded systems - knurling-rs/defmt
Блог*
#prog #моё Сегодня я хотел бы рассказать о возможных способах реализации полиморфизма в языках программирования и о том, какие выгоды и издержки они имеют. Disclaimer: я не особо шарю, так что могу наговорить глупостей. Полиморфизм — это свойство кода обрабатывать…
#prog #article
Разбор различных способов реализации полиморфизма, более обстоятельный и глубокий, чем у меня. Заодно показываются модели, которые пока что не получили должной реализации.
thume.ca/2019/07/14/a-tour-of-metaprogramming-models-for-generics/
Разбор различных способов реализации полиморфизма, более обстоятельный и глубокий, чем у меня. Заодно показываются модели, которые пока что не получили должной реализации.
thume.ca/2019/07/14/a-tour-of-metaprogramming-models-for-generics/
thume.ca
Models of Generics and Metaprogramming: Go, Rust, Swift, D and More - Tristan Hume
#prog
Мысли по поводу лучшего стабильного ABI, чем сишный. В виде треда в твиттере, сорян, в более удобоваримом формате нет.
twitter.com/bitshiftmask/status/1286411475658178561
Мысли по поводу лучшего стабильного ABI, чем сишный. В виде треда в твиттере, сорян, в более удобоваримом формате нет.
twitter.com/bitshiftmask/status/1286411475658178561
Twitter
james.poll_on()?;
Here's a rant (opinion?) that I'll turn in to a blog post soon. I think Rust should have a third ABI, not repr(C) or repr(Rust), and it should be used to slowly phase out the C ABI for a better one. Want to hear more of my unreasonable thoughts about ABIs?…
#prog #article
"So, although I don’t have any data to back this up, I strongly suspect that experienced programmers rarely spend time posting about how they program because they just don’t think it’s anything special.
But they should! It may not be special, but it’s necessary, and if good programmers don’t start posting about how to do good programming, we’ll never get out of this nasty place where everyone has to go through six years of writing horrible object-oriented programs before they realize they’re wasting their time."
caseymuratori.com/blog_0015
"So, although I don’t have any data to back this up, I strongly suspect that experienced programmers rarely spend time posting about how they program because they just don’t think it’s anything special.
But they should! It may not be special, but it’s necessary, and if good programmers don’t start posting about how to do good programming, we’ll never get out of this nasty place where everyone has to go through six years of writing horrible object-oriented programs before they realize they’re wasting their time."
caseymuratori.com/blog_0015
Semantic Compression
An introduction to the idea that code should be approached with a mindset towards compressing it semantically, rather than orienting it around objects.
#prog #article
Дежурное напоминание, что S в IoT означает Security.
habr.com/ru/company/ruvds/blog/517638/
Дежурное напоминание, что S в IoT означает Security.
habr.com/ru/company/ruvds/blog/517638/
Хабр
Shodan — темный близнец Google
Источник S in IoT stands for SecurityПро Shodan уже не раз писали, в том числе и здесь. Я хочу предложить еще раз пробежаться по возможностям этого замечательного инструмента и принципам его...
#prog #rust #article
Буквально мои мысли читает. TL;DR: если у вас есть
matklad.github.io/2020/08/12/who-builds-the-builder.html
Буквально мои мысли читает. TL;DR: если у вас есть
Foo
и FooBuilder
, добавьте метод Foo::builder
.matklad.github.io/2020/08/12/who-builds-the-builder.html
matklad.github.io
Who Builds the Builder?
This is a short note on the builder pattern, or, rather, on the builder method pattern.
#prog #rust #article
Я считаю, что в дизайне современных языков программирования упущена весьма важная тема: перекрывающийся доступ к значениям (aliasing). В статье Niko Matsakis (старой, написанной ещё в те времена, когда в Rust ещё был сборщик мусора) раскрывается связь между управлением памятью и отсутствием гонок данных. В статье Manish Goregaokar эта тема раскрыто несколько более глубоко, а в статье Matt Brubeck рассказывается, в частности, о том, как связаны мутабельность и уникальность доступа и как можно построить безопасные API поверх небезопасного, предоставляющего безусловное перекрытие доступа.
И да, если вы считаете, что это исключительно бзик Rust, то вот вам статьи о аналогичных механизмах в Swift и D.
Я считаю, что в дизайне современных языков программирования упущена весьма важная тема: перекрывающийся доступ к значениям (aliasing). В статье Niko Matsakis (старой, написанной ещё в те времена, когда в Rust ещё был сборщик мусора) раскрывается связь между управлением памятью и отсутствием гонок данных. В статье Manish Goregaokar эта тема раскрыто несколько более глубоко, а в статье Matt Brubeck рассказывается, в частности, о том, как связаны мутабельность и уникальность доступа и как можно построить безопасные API поверх небезопасного, предоставляющего безусловное перекрытие доступа.
И да, если вы считаете, что это исключительно бзик Rust, то вот вам статьи о аналогичных механизмах в Swift и D.
#prog #rust #моё
Исторически решение задач с бектрекингом является более простым в функциональных ЯП с персистентными структурами данных. Взял состояние, немного поменял его и получил новую версию, делаешь на ней рекурсивный вызов, если решение зашло в тупик — возвращаешься обратно и работаешь со старой версией состояния. Благодаря должной реализации и заточенным под работу с иммутабельными данными компилятору это даже может достаточно эффективно работать. Императивные ЯП обычно обделены подобной роскошью. Даже если есть реализация подобной структуры данных, работает она зачастую менее эффективно полноценно изменяемой структуры данных. Из-за этого в решении задач с бектрекингом появляется некоторая структура данных, которая умеет отменять изменения. Это несколько неудобно и чревато ошибками.
Я задумался над тем, как можно упростить подобное решение, не потеряв эффективности мутабельных изменений, и, кажется, нашёл тот краеугольный камень, с помощью которого можно выстроить такую инфраструктуру, подобно тому, как все методы Iterator определены через Iterator::next. Это трейт
Дополнительное требование к реализации, которое, увы, невыразимо в коде на Rust (но было бы выразимо на, скажем, Agda или Idris), состоит в том, что изменение, возвращённое apply, будучи применённым обратно к self, переводит его в первоначальное состояние (до степени, требуемой задачей: это изменение может поменять, скажем, ёмкость хэшмапы, но навряд ли для вас это существенно). Иными словами,
Данное определение вкупе с приведённым выше требованием обеспечивает композируемость и, как следствие, линейную историю. Скажем,
Если несколько изменить способ хранений изменений и не отбрасывать их, то можно также реализовать redo.
Вот несколько более изощрённый пример, который применяет отменяющие патчи автоматически, когда изменённая версия становится не нужна:
Этот метод уже по эргономике приближается к варианту с персистентными структурами данных: если мы в каждый момент времени работаем только с одной версией структуры, то этого достаточно, при этом нам не требуется применять отмену руками, всё происходит автоматически.
Исторически решение задач с бектрекингом является более простым в функциональных ЯП с персистентными структурами данных. Взял состояние, немного поменял его и получил новую версию, делаешь на ней рекурсивный вызов, если решение зашло в тупик — возвращаешься обратно и работаешь со старой версией состояния. Благодаря должной реализации и заточенным под работу с иммутабельными данными компилятору это даже может достаточно эффективно работать. Императивные ЯП обычно обделены подобной роскошью. Даже если есть реализация подобной структуры данных, работает она зачастую менее эффективно полноценно изменяемой структуры данных. Из-за этого в решении задач с бектрекингом появляется некоторая структура данных, которая умеет отменять изменения. Это несколько неудобно и чревато ошибками.
Я задумался над тем, как можно упростить подобное решение, не потеряв эффективности мутабельных изменений, и, кажется, нашёл тот краеугольный камень, с помощью которого можно выстроить такую инфраструктуру, подобно тому, как все методы 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);
}
}
Этот метод уже по эргономике приближается к варианту с персистентными структурами данных: если мы в каждый момент времени работаем только с одной версией структуры, то этого достаточно, при этом нам не требуется применять отмену руками, всё происходит автоматически.
Wikipedia
Persistent data structure
data structure that always preserves the previous version of itself when it is modified
👍2