Блог*
#prog #rust Generic associated types to be stable in Rust 1.65 АААААААААААААААААААААА
Да, вышла версия сегодня! Чуть позднее распишу детали
🎉11👍1
#prog #rust #rustreleasenotes
Вышла версия Rust 1.65.0! Как всегда, вычленю только то, что интересно мне, за подробностями в RELEASES.md.
▪️Generic associated types (GAT) стабилизировали. Не буду повторять ещё раз, почему это так важно, и просто покажу пачку примеров из официального блогопоста:
▪️
▪️По поводу того, являются ли неинициализированные числа UB, долгое время не было консенсуса. В частности, в документации
(Notice that the rules around uninitialized integers are not finalized yet, but until they are, it is advisable to avoid them.)
Так вот, теперь эти правила прописаны: записывание неинициализированных битов в значения примитивных типов теперь является немедленным неопределённым поведением, даже если результат не используется. Минус одно неясное место для unsafe-кода.
▪️Изменение, о котором я уже говорил: компилятор теперь лучше эксплуатирует ниши в перечислениях для оптимизации представления значений типов в памяти.
▪️Стабилизированы нативные бектрейсы.
▪️Стабилизирована
Read all bytes from a reader into a new
This is a convenience function for
▪️RLS всё
▪️Парочка оптимизаций компиляции. Во-первых, cargo теперь лучше учитывает приоритеты зависимостей при компиляции. Во-вторых, компилятор теперь использует встраивание кода на уровне MIR. Оба улучшения показали свою эффективность на реальном коде.
▪️И ещё одно улучшение компиляции: компилятор теперь поддерживает вынос отладочных символов в отдельн(ый, ые) объектные файлы. Это может ускорить компиляцию за счёт снижения работы, которую нужно выполнять линковщику. По умолчанию, однако, это поведение всё ещё отключено.
Вышла версия Rust 1.65.0! Как всегда, вычленю только то, что интересно мне, за подробностями в RELEASES.md.
▪️Generic associated types (GAT) стабилизировали. Не буду повторять ещё раз, почему это так важно, и просто покажу пачку примеров из официального блогопоста:
/// An `Iterator`-like trait that can borrow from `Self`
trait LendingIterator {
type Item<'a> where Self: 'a;
fn next<'a>(&'a mut self) ->
Option<Self::Item<'a>>;
}
/// Can be implemented over smart pointers, like `Rc` or `Arc`,
/// in order to allow being generic over the pointer type
trait PointerFamily {
type Pointer<T>: Deref<Target = T>;
fn new<T>(value: T) -> Self::Pointer<T>;
}
/// Allows borrowing an array of items. Useful for
/// `NdArray`-like types that don't necessarily store
/// data contiguously.
trait BorrowArray<T> {
type Array<'x, const N: usize> where Self: 'x;
fn borrow_array<'a, const N: usize>(&'a self)
-> Self::Array<'a, N>;
}
▪️let
теперь можно использовать с refutable паттернами. В этом случае за выражением должна следовать ветка else
с фигурными скобками, в которых должно быть выражение типа !
. Небольшой пример:let (Some(x), Some(y)) = (iter.next(), iter.next()) else {
return Err(Error::UnsufficientItems)
};
Лично я частенько писал код с if let
, который делает ранний возврат в else
, так что для меня это определённо позитивное изменение. С другой стороны, в общем случае сказать, не видя определения, является ли паттерн refutable или нет, нельзя, что может сказаться на читаемости при злоупотреблении. В общем, практика покажет.▪️
break
теперь можно использовать внутри любых блоков с меткой, а не только циклов, и при этом ещё и возвращать значение. Таким образом можно делать ранний возврат в рамках блока, а не функции целиком:let result = 'block: {
do_thing();
if condition_not_met() {
break 'block 1;
}
do_next_thing();
if condition_not_met() {
break 'block 2;
}
do_last_thing();
3
};
До этого изменения люди имитировали этот функционал в реальном коде с использованием loop
, который делал лишь одну итерацию. С использованием этой фичи можно гораздо лучше передавать намерения.▪️По поводу того, являются ли неинициализированные числа UB, долгое время не было консенсуса. В частности, в документации
MaybeUninit
долгое время было написано:(Notice that the rules around uninitialized integers are not finalized yet, but until they are, it is advisable to avoid them.)
Так вот, теперь эти правила прописаны: записывание неинициализированных битов в значения примитивных типов теперь является немедленным неопределённым поведением, даже если результат не используется. Минус одно неясное место для unsafe-кода.
▪️Изменение, о котором я уже говорил: компилятор теперь лучше эксплуатирует ниши в перечислениях для оптимизации представления значений типов в памяти.
▪️Стабилизированы нативные бектрейсы.
▪️Стабилизирована
std::io::read_to_string
:Read all bytes from a reader into a new
String
.This is a convenience function for
Read::read_to_string
. Using this function avoids having to create a variable first and provides more type safety since you can only get the buffer out if there were no errors. (If you use Read::read_to_string
you have to remember to check whether the read succeeded because otherwise your buffer will be empty or only partially full.)▪️RLS всё
▪️Парочка оптимизаций компиляции. Во-первых, cargo теперь лучше учитывает приоритеты зависимостей при компиляции. Во-вторых, компилятор теперь использует встраивание кода на уровне MIR. Оба улучшения показали свою эффективность на реальном коде.
▪️И ещё одно улучшение компиляции: компилятор теперь поддерживает вынос отладочных символов в отдельн(ый, ые) объектные файлы. Это может ускорить компиляцию за счёт снижения работы, которую нужно выполнять линковщику. По умолчанию, однако, это поведение всё ещё отключено.
🔥19🎉6❤4😱1
Сегодня мне приснилась некая азиатская (вроде) страна, которая была баснословно богатой (кажется, за счёт экспорта ценного сырья), но при этом в ужасающем состоянии. Принцип "казаться, а не быть" там был возведён в абсолют: для того, чтобы создать видимость радостного народа, возвели повсюду аниматроников из человеческих тел, а чтобы скрыть тотальную разруху и отсутствие нормальной инфраструктуры и создать видимость солнечной, счастливой страны — всюду постоянно распыляли наркотики, которые заставляли воспринимать реальность так, как нужно, и заставляли аниматроников выглядеть, как реальных людей. И ещё на руках у правителя этой страны было жуткое оружие — некая "мили-бомба", которая буквально уничтожала время — и он не боялся подорвать её у себя в стране, потому что она и так безнадёжно застряла в прошлом.
К чему бы это?
К чему бы это?
🤔6💩1
Блог*
Сегодня мне приснилась некая азиатская (вроде) страна, которая была баснословно богатой (кажется, за счёт экспорта ценного сырья), но при этом в ужасающем состоянии. Принцип "казаться, а не быть" там был возведён в абсолют: для того, чтобы создать видимость…
Да, я читал "Футурологический конгресс" Станислава Лема
❤4👍1
#rust #article
Do we need a "Rust Standard"?
While this comes down to a definition question, standardization is usually associated with the work done by a “standardization body” such as ISO or ECMA: an organisation that takes responsibility for the coordination of the evolution of a standard. These organisations have processes through which stakeholders from all over the world can participate in the evolution of the technologies they standardize.
However, in the Rust Project, we already have an open process for evolving the language, based on RFCs, team consensus, and unstable experimentation. Handing off the responsibility to a standards organisation means giving up our control, with little to no benefit. We’d lose our ability to shape the processes the way we think works best, and we might no longer be able to guarantee an open and inclusive environment that’s up to our standards.
Many companies and individuals participate in C++ standardization to influence the language; to add their own feature to the language. However, an effort towards a Rust specification is not about changing Rust. We already have a process for changing Rust, and the companies I’ve spoken to that would benefit from a Rust specification are actually not interested in changing the ways in which they can influence the evolution of the language.
Do we need a "Rust Standard"?
While this comes down to a definition question, standardization is usually associated with the work done by a “standardization body” such as ISO or ECMA: an organisation that takes responsibility for the coordination of the evolution of a standard. These organisations have processes through which stakeholders from all over the world can participate in the evolution of the technologies they standardize.
However, in the Rust Project, we already have an open process for evolving the language, based on RFCs, team consensus, and unstable experimentation. Handing off the responsibility to a standards organisation means giving up our control, with little to no benefit. We’d lose our ability to shape the processes the way we think works best, and we might no longer be able to guarantee an open and inclusive environment that’s up to our standards.
Many companies and individuals participate in C++ standardization to influence the language; to add their own feature to the language. However, an effort towards a Rust specification is not about changing Rust. We already have a process for changing Rust, and the companies I’ve spoken to that would benefit from a Rust specification are actually not interested in changing the ways in which they can influence the evolution of the language.
blog.m-ou.se
Do we need a "Rust Standard"?
Languages like C and C++ are standardized.
They are fully specified in an internationally recognized standards document.
Languages like Python, Swift and Rust do not have such a standards document.
Should Rust be standardized? Why, or why not?
In this blog…
They are fully specified in an internationally recognized standards document.
Languages like Python, Swift and Rust do not have such a standards document.
Should Rust be standardized? Why, or why not?
In this blog…
🔥8💩1
#prog #rust #performancetrap #article
The stable HashMap trap
You read about faster hash functions and switch to one. Most of your code gets the expected speed boost, but some parts mysteriously get slower – much slower, especially when dealing with large hashmaps. If this sounds familiar, you might have encountered the stable HashMap trap.
The stable HashMap trap
You read about faster hash functions and switch to one. Most of your code gets the expected speed boost, but some parts mysteriously get slower – much slower, especially when dealing with large hashmaps. If this sounds familiar, you might have encountered the stable HashMap trap.
More Stina Blog!
The stable HashMap trap
You read about faster hash functions and switch to one. Most of your code gets the expected speed boost, but some parts mysteriously get slower – much slower, especially when dealing with lar…
💩1
Делать ли отдельный хештег под неочевидные способы потерять производительность?
Final Results
80%
Да
5%
Нет
16%
Кешбери
🤮1💩1
Forwarded from Министерство пиздохаханек и смехуёчков
Знаете как назвать гея, который поддерживает спецоперацию?
Виталий Милонов
😁15😐8🤮2💩1
Forwarded from Кустарный мыслепоток (Konstantin Redkin)
Ситуация "Умный дом". Привык, что дома включаю и выключаю свет через Алису. Пошёл выключать чайник, подхожу к газовой плите; и железному чайнику со свистком говорю: "Алиса, выключи чайник". Лишь через секунд 5 до меня дошло, что чайник-то обычный и свистит вполне себе паром, а не динамиками.
Похоже пора покупать умный чайник.
Похоже пора покупать умный чайник.
❤3😁2🤔2💩1
Блог*
#rust poignardazur.github.io/2022/11/05/political-messages-in-the-rust-blog (thanks @rustamann)
Алсо ОФИГЕТЬ, НОВЫЙ ПОСТ В RUSTA::MANN
👍3🔥2💩1
И днём и ночью кот учёный
Всё ходит по цепи кругом
Потому что блоки для блокчейна майнит
Всё ходит по цепи кругом
Потому что блоки для блокчейна майнит
😁16👎4❤2👍2💩1🤡1
Блог*
#math #video To me, the monster and it's absurd size is a nice reminder that fundamental objects are not necessarily simple. The universe doesn't really care if its final answers look clean; they are what they are by logical necessity, with no concern over…
И, на самом деле, на подтверждение этого тезиса я натыкаюсь постоянно.
Эволюцию волновой функции со временем — аналог второго закона Ньютона из классической механики — описывается уравнением Шрёдингера. Чисто технически из него можно вывести всю физику атомов, и, следовательно, и всю химию — но это чёртово уравнение в частных производных, и оно имеет достаточно сложную структуру, чтобы оно имело аналитическое решение лишь для очень частных случаев. В частности, для одиночного атома водорода существует аналитическое решение, а вот для атома гелия — уже нет.
Ладно, возьмём что попроще: течение жидкости, причём на скоростях, когда ньютоновская механика даёт достаточно адекватное приближение (читай, для всех летательных аппаратов). Течение ньютоновской жидкости описывается уравнением Навье-Стокса. Казалось бы, описание движения водички не должно составлять проблем, так ведь? Как бы ни так: это уравнение является не только уравнением в частных производных, но и уравнением нелинейным (чем, кстати, существенно отличается от уравнения Шрёдингера), потому найти его аналитическое решение весьма тяжело даже при наложении имеющих физический смысл ограничений вроде неразрывности и несжимаемости (а сжимаемостью пренебречь при расчёте характеристик самолётов нельзя). Даже сам вопрос о наличии гладкого и ограниченного решения при гладких и ограниченных начальных значениях и внешних условиях остаётся одной из нерешённых математических проблем.
Да бог с ней, с водой — возьмём что ещё проще. Скажем, колеблющуюся струну, и опять в максимально идеализированном виде — когда мы можем притвориться, что сила натяжения, действующая на участок струны, пропорциональна его смещению относительно соседних участков. Это — тоже уравнение в частных производных, причём в отсутствие внешних сил — линейное. Казалось бы, оно легко решается, ведь так? Ну, в принципе, да, вот только решение включает в себя интегралы от начальных условий. И если производная от композиции элементарных функций выражается через композицию элементарных функций, то аналогичное утверждение насчёт интегралов неверно: даже такая простая функция, как
Ладно, а если мы откажемся от непрерывности и переместимся в область дискретной математики, станут ли дела проще? В конце-концов, есть же такая простая вещь, как лямбда-исчисление, которое не хуже машины Тьюринга годится для формализации алгоритмов. Однако в определении лямбда-исчисления входит понятие переменной — и, как оказывается, для моделирования вычислений достаточно лишь понятия функции и аппликации, что показывает комбинаторная логика. Обычно в качестве базиса в комбинаторной логике выделяют комбинаторы K, S и I:
Ix = x
Kxy = x
Sxyz = xz(yz)
, и если поведение I и K ясно и легко описывается, то коротко охарактеризовать поведение S не выходит. Более того, этот базис, вообще говоря, избыточен, поскольку I описывается в терминах S и K:
((S K K) x)
= (S K K x)
= (K x (K x))
= x
Можно ли уменьшить этот базис? Можно! Для построения всех комбинаторов достаточно одного комбинатора ι (йота), поведение которого можно определить в терминах термов лямбда-исчисления:
ι := λf. ((f λa. λb. λc. ((ac)(bc)))λd. λe. d)
Или, в терминах SK:
ι := λf. ((fS)K)
Я затрудняюсь сформулировать хотя бы приблизительно семантику этой вещи, но этого комбинатора достаточно, чтобы построить на его базе целый язык программирования, программы на котором используют всего два символа.
Ладно, упростим ещё больше: перейдём к булевой алгебре. Нет, сама булева алгебра проста, как сапог, но вот наборы аксиом, которые её задают, зачастую избыточны. Насколько сильно можно уменьшить этот набор? Как показал Стивен Вольфрам (основатель Wolfram|Alpha), для булевой алгебры достаточно всего одной аксиомы об операции NAND (здесь обозначаемой стрелкой, так как эта функция также известна, как стрелка Пирса):
((p↑q)↑r)↑(p↑((p↑r)↑p)) = r
Базис аксиоматики? Безусловно. Просто? Я бы сказал, что нет.
Эволюцию волновой функции со временем — аналог второго закона Ньютона из классической механики — описывается уравнением Шрёдингера. Чисто технически из него можно вывести всю физику атомов, и, следовательно, и всю химию — но это чёртово уравнение в частных производных, и оно имеет достаточно сложную структуру, чтобы оно имело аналитическое решение лишь для очень частных случаев. В частности, для одиночного атома водорода существует аналитическое решение, а вот для атома гелия — уже нет.
Ладно, возьмём что попроще: течение жидкости, причём на скоростях, когда ньютоновская механика даёт достаточно адекватное приближение (читай, для всех летательных аппаратов). Течение ньютоновской жидкости описывается уравнением Навье-Стокса. Казалось бы, описание движения водички не должно составлять проблем, так ведь? Как бы ни так: это уравнение является не только уравнением в частных производных, но и уравнением нелинейным (чем, кстати, существенно отличается от уравнения Шрёдингера), потому найти его аналитическое решение весьма тяжело даже при наложении имеющих физический смысл ограничений вроде неразрывности и несжимаемости (а сжимаемостью пренебречь при расчёте характеристик самолётов нельзя). Даже сам вопрос о наличии гладкого и ограниченного решения при гладких и ограниченных начальных значениях и внешних условиях остаётся одной из нерешённых математических проблем.
Да бог с ней, с водой — возьмём что ещё проще. Скажем, колеблющуюся струну, и опять в максимально идеализированном виде — когда мы можем притвориться, что сила натяжения, действующая на участок струны, пропорциональна его смещению относительно соседних участков. Это — тоже уравнение в частных производных, причём в отсутствие внешних сил — линейное. Казалось бы, оно легко решается, ведь так? Ну, в принципе, да, вот только решение включает в себя интегралы от начальных условий. И если производная от композиции элементарных функций выражается через композицию элементарных функций, то аналогичное утверждение насчёт интегралов неверно: даже такая простая функция, как
sin(x) / x
, имеет первообразную, невыразимую в элементарных функциях, и носящую собственное имя.Ладно, а если мы откажемся от непрерывности и переместимся в область дискретной математики, станут ли дела проще? В конце-концов, есть же такая простая вещь, как лямбда-исчисление, которое не хуже машины Тьюринга годится для формализации алгоритмов. Однако в определении лямбда-исчисления входит понятие переменной — и, как оказывается, для моделирования вычислений достаточно лишь понятия функции и аппликации, что показывает комбинаторная логика. Обычно в качестве базиса в комбинаторной логике выделяют комбинаторы K, S и I:
Ix = x
Kxy = x
Sxyz = xz(yz)
, и если поведение I и K ясно и легко описывается, то коротко охарактеризовать поведение S не выходит. Более того, этот базис, вообще говоря, избыточен, поскольку I описывается в терминах S и K:
((S K K) x)
= (S K K x)
= (K x (K x))
= x
Можно ли уменьшить этот базис? Можно! Для построения всех комбинаторов достаточно одного комбинатора ι (йота), поведение которого можно определить в терминах термов лямбда-исчисления:
ι := λf. ((f λa. λb. λc. ((ac)(bc)))λd. λe. d)
Или, в терминах SK:
ι := λf. ((fS)K)
Я затрудняюсь сформулировать хотя бы приблизительно семантику этой вещи, но этого комбинатора достаточно, чтобы построить на его базе целый язык программирования, программы на котором используют всего два символа.
Ладно, упростим ещё больше: перейдём к булевой алгебре. Нет, сама булева алгебра проста, как сапог, но вот наборы аксиом, которые её задают, зачастую избыточны. Насколько сильно можно уменьшить этот набор? Как показал Стивен Вольфрам (основатель Wolfram|Alpha), для булевой алгебры достаточно всего одной аксиомы об операции NAND (здесь обозначаемой стрелкой, так как эта функция также известна, как стрелка Пирса):
((p↑q)↑r)↑(p↑((p↑r)↑p)) = r
Базис аксиоматики? Безусловно. Просто? Я бы сказал, что нет.
Physics Stack Exchange
Why are analytical solutions of the Schrödinger equation available only for a small number of simple models?
As it turns out, analytic solutions of the Schrödinger equation are available for only a very small number of relatively simple model Hamiltonians, of which the quantum harmonic oscillator, the par...
👍9🔥5
Но и в чисто прикладных вещах этот тезис получает своё подтверждение. Лично мне на ум приходит понятие итераторов (на всякий случай: сказанное ниже в основном относится к external iterator). Казалось бы, операции типа map, filter и fold/reduce куда проще определить непосредственно на коллекциях (и, собственно, в Javascript и Kotlin так и делают). Понятие итератора уже является некоторой абстракцией, полезность которой не ясна с первого взгляда, а уж комбинатор итераторов является абстракцией высшего порядка: он принимает итератор на вход и выдаёт итератор на выход. Казалось бы, к чему эти усложнения, почему нельзя обойтись монолитными операциями? В пользу итераторов есть несколько аргументов (впрочем, сильно завязанных друг на друга):
Ленивость: итератор не делает ничего, пока его о чём-то не попросят. Ленивость позволяет обрабатывать данные из источников, которые в развёрнутом виде не влезают в память — либо потому, что они в принципе бесконечны, либо потому, что банально слишком крупные для этого (файл на диске запросто может быть слишком велик, чтобы уместиться в свободное место в оперативке).
Выразительность: с помощью итераторов можно выразить то, что невозможно выразить на ограниченном наборе монолитных операций. Например, имея на руках map, невозможно в его терминах выразить операцию zip, для которой требуется перебирать последовательности синхронно друг с другом. Имея абстракцию итераторов, можно написать zip самостоятельно, в случае же с монолитными операциями мы вынуждены внести в набор примитивных операция zip... Для каждой пары коллекций! Другой пример — раннее прерывание итерации по какому-то условию. Опять-таки, вызывающий код контролирует, когда итератор выдаёт элементы, и потому ничто не мешает ему самостоятельно принимать решение, когда итерацию прерывать (и начинать ли её вовсе). В случае с монолитными операциями нет никакой возможности вклиниться в процесс итерации. Также можно упомянуть операции над данными, которые материализуются на лету, например, вычисляются или считываются по сети. Для таких источников операция map, сохраняющая тип "коллекции", попросту не имеет смысла, итераторы же работают с этим без проблем.
Расширяемость: мы (как правило) не можем переписать реализацию методов для чужих типов или добавлять свои (а даже если и можем, это, как правило, считается дурным тоном). Выделение же промежуточной абстракции позволяет расширять итераторные операции: как за счёт добавления преобразований в итераторы для существующих типов, так и за счёт добавления новых комбинаторов. С монолитными операциями добавление новых комбинаторов, равно как и итерируемых объектов, требует линейного количества работы — по реализации метода для каждой из уже итерируемой коллекции в первом случае и по реализации каждого из уже имеющихся методов для новой коллекции во втором. В случае же с итераторами количество работы при расширении таблицы в обе стороны константно.
Производительность: обработка по одному элементу за раз при достаточном количестве данных, требуемых обработки, требует меньше ресурсов, чем аналогичные монолитные методы, выделяющие по коллекции на каждый промежуточный шаг.
===
В заключение хотелось бы привести пример, когда этот принцип, судя по всему, не выполняется: аксиоматика евклидовой геометрии. Оригинальный набор аксиом, записанный Евклидом в "Началах", был избыточен, и со временем его удалось сократить. Однако пятый постулат, который упорно сопротивлялся попыткам быть доказанным (и, как оказалось, неспроста — в процессе математики открыли неевклидовы геометрии), во многом выглядел как что-то, что можно доказать, из-за крайне громоздкой формулировки самого Евклида:
И если прямая, падающая на две прямые, образует внутренние и по одну сторону углы, меньшие двух прямых, то продолженные неограниченно эти прямые встретятся с той стороны, где углы меньше двух прямых.
В современном изложении планиметрии эту аксиому обычно заменяют эквивалентной аксиомой о параллельной прямой:
В плоскости через точку, не лежащую на данной прямой, можно провести одну и только одну прямую, параллельную данной.
Ленивость: итератор не делает ничего, пока его о чём-то не попросят. Ленивость позволяет обрабатывать данные из источников, которые в развёрнутом виде не влезают в память — либо потому, что они в принципе бесконечны, либо потому, что банально слишком крупные для этого (файл на диске запросто может быть слишком велик, чтобы уместиться в свободное место в оперативке).
Выразительность: с помощью итераторов можно выразить то, что невозможно выразить на ограниченном наборе монолитных операций. Например, имея на руках map, невозможно в его терминах выразить операцию zip, для которой требуется перебирать последовательности синхронно друг с другом. Имея абстракцию итераторов, можно написать zip самостоятельно, в случае же с монолитными операциями мы вынуждены внести в набор примитивных операция zip... Для каждой пары коллекций! Другой пример — раннее прерывание итерации по какому-то условию. Опять-таки, вызывающий код контролирует, когда итератор выдаёт элементы, и потому ничто не мешает ему самостоятельно принимать решение, когда итерацию прерывать (и начинать ли её вовсе). В случае с монолитными операциями нет никакой возможности вклиниться в процесс итерации. Также можно упомянуть операции над данными, которые материализуются на лету, например, вычисляются или считываются по сети. Для таких источников операция map, сохраняющая тип "коллекции", попросту не имеет смысла, итераторы же работают с этим без проблем.
Расширяемость: мы (как правило) не можем переписать реализацию методов для чужих типов или добавлять свои (а даже если и можем, это, как правило, считается дурным тоном). Выделение же промежуточной абстракции позволяет расширять итераторные операции: как за счёт добавления преобразований в итераторы для существующих типов, так и за счёт добавления новых комбинаторов. С монолитными операциями добавление новых комбинаторов, равно как и итерируемых объектов, требует линейного количества работы — по реализации метода для каждой из уже итерируемой коллекции в первом случае и по реализации каждого из уже имеющихся методов для новой коллекции во втором. В случае же с итераторами количество работы при расширении таблицы в обе стороны константно.
Производительность: обработка по одному элементу за раз при достаточном количестве данных, требуемых обработки, требует меньше ресурсов, чем аналогичные монолитные методы, выделяющие по коллекции на каждый промежуточный шаг.
===
В заключение хотелось бы привести пример, когда этот принцип, судя по всему, не выполняется: аксиоматика евклидовой геометрии. Оригинальный набор аксиом, записанный Евклидом в "Началах", был избыточен, и со временем его удалось сократить. Однако пятый постулат, который упорно сопротивлялся попыткам быть доказанным (и, как оказалось, неспроста — в процессе математики открыли неевклидовы геометрии), во многом выглядел как что-то, что можно доказать, из-за крайне громоздкой формулировки самого Евклида:
И если прямая, падающая на две прямые, образует внутренние и по одну сторону углы, меньшие двух прямых, то продолженные неограниченно эти прямые встретятся с той стороны, где углы меньше двух прямых.
В современном изложении планиметрии эту аксиому обычно заменяют эквивалентной аксиомой о параллельной прямой:
В плоскости через точку, не лежащую на данной прямой, можно провести одну и только одну прямую, параллельную данной.
MDN Web Docs
Array.prototype.map() - JavaScript | MDN
The map() method of Array instances creates
a new array populated with the results of calling a provided function on
every element in the calling array.
a new array populated with the results of calling a provided function on
every element in the calling array.
👍4🔥1
Хоспаде, изначально я хотел этот пост написать сразу после публикации того видео от 3b1b. Почему на это ушла целая неделя?
#prog #php #cpp #article
Как мы наш большой проект на KPHP мигрировали
Безумству храбрых поём мы песню
Как мы наш большой проект на KPHP мигрировали
Безумству храбрых поём мы песню
Хабр
Как мы наш большой проект на KPHP мигрировали
История о том, как мы мигрировали нашу систему управления проектами на KPHP. Если у вас есть PHP-проект с длинной историей и вы хотите запуститься на KPHP для получения выгод, то приготовьтесь! Будет...
😱5🔥2