LINUX.ORG.RU

into_rust() — скринкасты по Rust. Доступно видео с RustConf 2016.

 , rustconf, ,


7

5

into_rust() — это плод годовой работы Николаса Мацакиса, одного из основных членов команды разработчиков Rust, и представляет из себя хранилище обучающих скринкастов по данному языку программирования. Обучение строится вокруг принципа работы с памятью в Rust: владение и заимствование.

На сайте (на момент написания новости) уже представлены следующие скринкасты:

На будущее запланированы следующие темы:

  • Structs and enums;
  • Threads;
  • Traits;
  • Named lifetime parameters;
  • Aliasing and mutability.

Исходный код сайта, включая слайды, доступен на GitHub. Автор приветствует любую помощь и замечания и просит открыть тикет, если вы нашли ошибку или хотите предложить улучшение.

Также стали доступны видеозаписи с прошедшей 10 сентября первой конференции по Rust — RustConf 2016.

Для просмотра доступны:

>>> Подробности

★★★★★

Проверено: Shaman007 ()
Последнее исправление: sudopacman (всего исправлений: 8)
Ответ на: комментарий от eao197

В случае исключения раскручивается стек с очисткой ресурсов до точки, где можно что-то предпринять. Если такой точки в программе нет, тогда уже можно и упасть. А если есть, то можно, например, отрицательный ответ сгенерировать или повторить операцию с другим набором параметров. Тут уже от прикладной задачи зависит.

Я вижу, надо пояснять. Ловля эксепшенов бывает двух типов, один - это когда ловится конкретное исключение в конкретном месте потому что создание этого исключения - штатная, ожидаемая ситуация. Раст в таком случае использует Result и о возможных ошибках сообщает прототип функции. Есть другие ошибки, которые «всё, туши свет, сливай воду», их конкретно никто никогда не ловит, они либо роняют приложение, либо ловятся каким-нибудь «catch(Throweble)» вокруг высокоуровневой функции типа «обработка запроса», и не делают ничего вменяемого, просто сообщают «не шмогла» и переходят к следующему запросу.

Так вот, для вторых случаев у раста уже есть «барьер» в виде потоков + экспериментируют с дополнительными возможностями добавить барьер без создания потока. Сейчас паника разворачивается до границы потока. Так что если проект настолько серьёзен, что нужно отключать OOM киллер в настройках ядра и обрабатывать ошибку нехватки памяти, то врубить режим паники через unwind и вынести обработку запроса в поток - не такая уж и сложная задача.

Проблему для нового человека составляют не такие вот серьёзные непредвиденные ошибки, а всякая мелочь типа НеНайденаИконкаДляКнопкиЭксепшен, потому что уволившийся 5 лет назад программист когда-то решил, что именно таким способом удобнее сообщать об отсутствии картинки, о чём вообще-то написано в 3000 строке в файле «\\Storage\Development\Documents\SuperSoft2000\...\Readme.txt» и вообще, мог бы спросить.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Так вот, для вторых случаев у раста уже есть «барьер» в виде потоков

Очень плохой барьер.

экспериментируют с дополнительными возможностями добавить барьер без создания потока. Сейчас паника разворачивается до границы потока.

IIRC, catch_unwind уже стабилизирован.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

IIRC, catch_unwind уже стабилизирован.

Пару версий уже как стабилизировали это api

grossws
()
Ответ на: комментарий от eao197

Но ни на один вопрос вы не ответили.

Хорошо, объясню проще: Не существует и не может существовать языка программирования, на котором можно было бы решать широкий круг задач, который при этом бы отлавливал все ошибки на этапе компиляции. Тем не менее любой язык программирования, даже ассемблер, спасает от какого-то класса ошибок. Раст в этом плане один из передовых языков, меньше информации приходится на документацию или устные договорённости, больше на проверяемый код. И дальше остаётся 2 вопроса: 1) согласны ли вы, что некоторые особенности раста (лайфтаймы, явное указание на возможность нулевого указателя, борроу чекер, явный возврат ошибки) позволяют избежать существенного класса неожиданностей при работе с малознакомым кодом? 2) согласны ли вы, что решение половины проблем - это лучше, чем не решение вообще?

Если ответы «да», то непонятно что вы тут делаете. Если хотя бы один ответ «нет», тогда уж напишите прямо, будет хотя бы понятно к чему это всё.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Вас куда-то не туда уносит. Вы выдвинули список претензий к C++. Среди них:

Всякая пурга типа «после того как сделал А, нужно сделать Б»
какая функция ... может исключение бросить

Я вас попросил показать, как эти проблемы решаются в Rust-е. Не нужно распинаться по поводу прогресса и пр. Просто покажите, чем Rust лучше в этих двух случаях.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Просто покажите, чем Rust лучше в этих двух случаях.

Про исключения в общем-то всё рассказано уже.

Про последовательность действий... ну вот, например, создание итератора коллекции, чтение из него, уничтожение итератора и изменение коллекции - это 4 операции, которые не могут совершаться в произвольном порядке. Захват мутекса, доступ к объекту и освобождение мутекса - тоже. Разделение вектора на слайсы, создание кучи потоков для обработки, доступ к слайсам в потоках, завершение потоков и доступ к вектору. Контроль над выполнением правильности последовательностей вовсю работает на RAII + borrow checker'е.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Про исключения в общем-то всё рассказано уже.

Простите, но ничего не сказано. Про то, что в Rust-е можно использовать АлгТД для возврата ошибок не прибегая к panic-ам, давно известно. Поэтому я просил рассказать, как быть при наличии panic-ов. Они в Rust-е не могут вылететь откуда угодно? Или на них можно просто забить?

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

?

По остальным пунктам такие же вопросы. Такое ощущение, что про современный C++ вам Рабинович по телефону напел.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

По остальным пунктам такие же вопросы.

Ну в С++ можно в процессе обхода вектора изменить его размер и компилятор никак не даст по рукам.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Вопрос в том, насколько часто это случается именно при обходе контейнера?

Бывают задачи, когда при обходе контейнера _нужно_ его же модифицировать. Но тут уж контроль со стороны компилятора скорее будет мешать, чем помогать.

Гораздо чаще случается ситуация, когда есть вектор, а в различных частях программы разбросаны ссылки на элементы этого вектора. В один прекрасный момент кто-то модифицирует вектор и ссылки протухают.

Но это не то, о чем говорил хрюндель.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Вопрос в том, насколько часто это случается именно при обходе контейнера?

Не знаю.

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

Ну почему? Да, придётся более явно намерения показать, но как по мне это наоборот хорошо. Ну и в данном контексте это скорее побочный бонус от ссылочной семантики в расте, чем специальная фича.

В один прекрасный момент кто-то модифицирует вектор и ссылки протухают.

И от этого раст тоже защитит. Ага, ценой дополнительных ограничений.

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 1)
Ответ на: комментарий от eao197

Простите, но ничего не сказано. Про то, что в Rust-е можно использовать АлгТД для возврата ошибок не прибегая к panic-ам, давно известно. Поэтому я просил рассказать, как быть при наличии panic-ов. Они в Rust-е не могут вылететь откуда угодно? Или на них можно просто забить?

Ну, значит вам давно известно, что штатные ошибки в расте трудно не обработать и они не вызовут неожиданное падение из-за того, что кто-то просто забыл поймать ошибку. Этого уже достаточно.

Но если важны именно паники - тоже в общем-то всё рассказали, либо падаем, либо ставим барьер. Большего как-то и хотеть нельзя.

По остальным пунктам такие же вопросы. Такое ощущение, что про современный C++ вам Рабинович по телефону напел.

Нет никакого «современного C++» в природе, это вас кто-то обманул. Реальный проект будет писаться людьми, которые изучали C++ по книгам 98го года. Но даже если б и был, и даже если бы кто-то потрудился нарушить все славные традиции и оформить в виде правильных RAII паттернов, толку было бы ноль: ну был бы у вас, например, мутекс как в расте, чтоб нельзя было получить указатель на данные в обход блокировки, один хрен этот указатель вы отдали бы в какую-то функцию, оттуда через цепочку вызовов он попал бы в другую функцию, автор которой мог и не догадываться, что полученный им параметр нельзя никуда сохранить, и привет, у вас ссылка на данные за незалоченным мутексом.

Уверяю вас, Бьярн Страуструп знает свой язык не хуже вас, и коль скоро он рекламирует C++ Core Guidelines, являющийся по сути подобием лайфтаймовой нотации раста, значит эта проблема существует и без явной поддержки со стороны языка её не решить. Ну а коль скоро всё равно нужно язык менять, зачем нужен недораст без паттернматчинга, ADT и с кучей устаревших решений, который и так не быстро компилируется, а ещё нужно анализатор запускать, чтоб убедиться в соответствии коре гайдлайнам, если есть нормальный раст?

khrundel ★★★★
()
Ответ на: комментарий от eao197

Бывают задачи, когда при обходе контейнера _нужно_ его же модифицировать. Но тут уж контроль со стороны компилятора скорее будет мешать, чем помогать.

Вас в сторону уносит. В контексте беседы итератор приведён как пример принуждения пользователя типа к правильному порядку действий. Авторы решили, что для безопасности изменение контейнера не должно производиться одновременно с существованием итераторов/слайсов/указателей на него и сделали так. Таким образом, если вы пишете некую подсистему со сложным контрактом, вы можете воспользоваться borrow checker'ом чтоб заставить вызывающую сторону его соблюдать.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Нет никакого «современного C++» в природе, это вас кто-то обманул.

Вы вообще программированием занимаетесь или на форумах трындите? А то вокруг меня реальность несколько другая.

и коль скоро он рекламирует C++ Core Guidelines, являющийся по сути подобием лайфтаймовой нотации раста, значит эта проблема существует и без явной поддержки со стороны языка её не решить

Лайфтаймы в GSL — это только часть GSL. Сам GSL — это сконцентрированный набор рекомендаций, накопившихся за годы использования C++.

Ну а коль скоро всё равно нужно язык менять

Язык можно менять эволюционно. Что и происходит со всеми успешными и долгоживущими языками.

зачем нужен недораст без паттернматчинга, ADT и с кучей устаревших решений, который и так не быстро компилируется, а ещё нужно анализатор запускать, чтоб убедиться в соответствии коре гайдлайнам, если есть нормальный раст?

Затем, что он есть уже 30 лет. И за это время на нем сделано столько, что вы даже не сможете себе представить.

eao197 ★★★★★
()
Ответ на: комментарий от khrundel

Таким образом, если вы пишете некую подсистему со сложным контрактом, вы можете воспользоваться borrow checker'ом чтоб заставить вызывающую сторону его соблюдать.

Покажите пример.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Язык можно менять эволюционно.

Хедеры выкинут - тогда заживём.

RazrFalcon ★★★★★
()
Ответ на: комментарий от eao197

Вы вообще программированием занимаетесь или на форумах трындите? А то вокруг меня реальность несколько другая.

Реальность такая, что многие программисты до сих пор собственную реализацию shared pointer пишут. Чисто по привычке. Сам видел.

Лайфтаймы в GSL — это только часть GSL. Сам GSL — это сконцентрированный набор рекомендаций, накопившихся за годы использования C++.

Хмм.. GSL - это Guidelines support library. Т.е. тупо набор тайпдефов аля owned<T*> = T*.

Сами гайдлайны называются «c++ core guidelines» и да, они включают больше чем просто лайфтаймы. Они включают owned<T*>, вот этот самый not_null<T*> и много других вещей, которые позаимствовали из раста. Кстати, эти самые гайдлайны лежат на гитхабе, первый коммит чуть больше года назад, т.е. уже после релиза раста, так что никаких сомнений на тему является ли cppcg попыткой догнать раст быть не может.

Не то чтоб вопрос первенства был так важен, просто не надо сочинять про «накопившиеся за годы использования».

Затем, что он есть уже 30 лет.

Полностью с вами согласен, пора отправлять на покой. Для сравнения: коболу 30 стукнуло в 89м, бейсику в 94м, паскалю в 2000м. Конечно, есть ещё старичок C, но так как он является просто портабельным ассемблером, ему позволительно жить дольше, в этой области мало что нового можно изобрести.

И за это время на нем сделано столько, что вы даже не сможете себе представить.

И пусть оно будет. И пусть куча программистов зарабатывают на поддержке кода. Просто старый софт под современный C++ портировать будут нечасто, а для новых проектов разумнее брать что-то более современное. Я, извините меня, уже в 2000х как-то сидел на поддержке/развитии проекта на C/X11/Motif и как-то даже мыслей не было предложить портировать это на C++/QT какие-нибудь. Возможно и сейчас какой-нибудь несчастный сидит и страдает на этом проекте. 90%+ от вашего «столько сделано» представляют собой примерно такие же проекты.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Реальность такая, что многие программисты до сих пор собственную реализацию shared pointer пишут. Чисто по привычке. Сам видел.

Прям многие? Может они следом еще и свои streams пишут, и вектора, и хеш-таблицы?

Не то чтоб вопрос первенства был так важен, просто не надо сочинять про «накопившиеся за годы использования».

Простите, вам сколько лет, если вы в GSL видите не зафиксированные в конце-концов в одной библиотеке best practices, а попытку угнаться за Rust-ом?

90%+ от вашего «столько сделано» представляют собой примерно такие же проекты.

Огромное количество нового кода создается либо прямо на базе старого кода, либо на переиспользовании кусков оттуда. В этом большое подспорье при работе с взрослым языком.

На любом новом языке придется ждать, пока накопится достаточное количество инструментов.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Прям многие? Может они следом еще и свои streams пишут, и вектора, и хеш-таблицы?

Ну, в моём случае правильный ответ «все», но я решил ограничиться более слабым утверждением, так как я видел только 2х и они работали вместе, возможно, один другого покусал. Хэш таблицы они, конечно же, не пишут, они пользуются старым добрым std::map.

Да, это анахронизм, но в реальности, если бы я устроился работать в их коллектив на проект с самодельным подсчётом ссылок, мне, скорее всего, пришлось бы подстраиваться.

Простите, вам сколько лет, если вы в GSL видите не зафиксированные в конце-концов в одной библиотеке best practices, а попытку угнаться за Rust-ом?

Вы спорьте не со мной, а с проклятой реальностью, в которой GSL - это библиотечка, первые опубликованная в августе прошлого года и, следовательно, не являющаяся частью ни многострадального C++11, ни 14. То же относится и к core guidelines (вы, почему-то упорно путаете эти понятия).

Да, вся эта пурга - это попытка сделать C++ подтяжку, чтоб стал похожим на rust. Если уж хотите вести холивар - говорите, что core guidelines - это такой «rust 2.0» и создана она как работа над ошибками в расте. Эта версия хотя бы истории не противоречит.

Огромное количество нового кода создается либо прямо на базе старого кода, либо на переиспользовании кусков оттуда. В этом большое подспорье при работе с взрослым языком.

Нет. Бывает поддержка старого кода, бывает развитие старого проекта, но обычно в определённый момент выясняется, что половина функциональности больше не нужна, сама структура проекта такова, что мешает дальнейшему развитию, а что-то уникальное, нужное, что не доступно в библиотеках и сложно переписать за пару месяцев составляет дай бог 5%. В итоге старый проект кладут в архив и выпускают новый почти с чистого листа. В нём меньше функций, но они все нужные и он поддерживает какую-нибудь хрень типа мобильников или работу через веб. И старого кода в нём или вообще нет, или в виде пары плагинов.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Ну, в моём случае правильный ответ «все», но я решил ограничиться более слабым утверждением, так как я видел только 2х

«Многие пишут свои умные указатели», «я видел только 2x»

facepalm.jpg

Да, вся эта пурга - это попытка сделать C++ подтяжку, чтоб стал похожим на rust. Если уж хотите вести холивар - говорите, что core guidelines - это такой «rust 2.0» и создана она как работа над ошибками в расте. Эта версия хотя бы истории не противоречит.

Вы когда-нибудь слышали про «после — не значит в следствии»?

Бывает поддержка старого кода, бывает развитие старого проекта, но обычно в определённый момент выясняется, что половина функциональности больше не нужна, сама структура проекта такова, что мешает дальнейшему развитию, а что-то уникальное, нужное, что не доступно в библиотеках и сложно переписать за пару месяцев составляет дай бог 5%. В итоге старый проект кладут в архив и выпускают новый почти с чистого листа.

Правда? И много вы таких проектов видели? Каков был их объем? И не было ли так, что для таких проектов C++ перестал быть хорошим выбором еще в 90-х?

eao197 ★★★★★
()
Ответ на: комментарий от loyd

Такое ощущение, что фанаты Rust-а искренне надеются, что Rust компенсирует им отсутствие мозга.

deque< unique_ptr< task > > tasks = get_initial_task_list();
while( !tasks.empty() ) {
  for( auto it = begin(tasks); it != tasks.end(); ) {
    if( it->completed() )
      it = tasks.erase(it);
    else {
      if( it->needs_split() )
        tasks.emplace_back( it->split() );
      ++it;
    }
  }
}
eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от eao197

«Многие пишут свои умные указатели», «я видел только 2x»

Вы не заметили, что уже на протяжении 3 сообщений минимум методично сливаетесь? По делу ни одного довода, только «мальчик, сколько тебе лет» и «а вот ты написал ..., а теперь докажи» и «ну это не 100% доказательство».

Вы можете не верить, но С++ доживает свой век. Новые фичи добавляются с большим запозданием, и реализованы криво, так как должны быть совместимыми со старым кодом, новые проекты предпочитают начинать на других языках. Всё что остаётся - молиться на старый код, который на modern C++ не похож вообще ни разу. Новые программисты изначально учатся на какой-нибудь питон и джаву, старые программисты пишут код как писали в начале 90х.

Правда? И много вы таких проектов видели? Каков был их объем?

Вы бы перестали огрызаться и вместо классического «а ты кто такой» взяли бы да привели контрпример.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Вы не заметили, что уже на протяжении 3 сообщений минимум методично сливаетесь?

Я заметил, что вы так и не смогли ответить на вопросы, которые вам были заданы (into_rust() — скринкасты по Rust. Доступно видео с RustConf 2016. (комментарий)). Но вот херни наговорили изрядно.

Вы можете не верить, но С++ доживает свой век.

С++ будет доживать свой век не меньше, чем Cobol.

Новые фичи добавляются с большим запозданием, и реализованы криво, так как должны быть совместимыми со старым кодом,

По сравнению с тем, как развивался C++ до 2011-го года, сейчас все просто в шоколаде.

новые проекты предпочитают начинать на других языках.

Ну, уж если сравнивать, как мало новых проектов начинают на Rust-е, в сравнении с количеством новых проектов на других языках, то у C++ еще все хорошо.

Всё что остаётся - молиться на старый код, который на modern C++ не похож вообще ни разу.

Может кто-то молится, не знаю. Знаю примеры, когда кодовую базу немаленького объема и возрастом более 10-15 лет тихо и спокойно дорабатывают, плавно переводя на новый C++.

Новые программисты изначально учатся на какой-нибудь питон и джаву,

Это нормально. Не всем нужно погружаться в околосистемное программирование или middleware.

старые программисты пишут код как писали в начале 90х.

Ну, если человек остановился в своем развитии, то да. Только вот он не будет конкурентоспособен в этой индустрии. Тут постоянно нужно учиться.

Вы бы перестали огрызаться и вместо классического «а ты кто такой» взяли бы да привели контрпример.

Контрпример чего? Где ваш пример, на который вы мне рекомендуете привести контрпример?

eao197 ★★★★★
()
Ответ на: комментарий от khrundel

Вот, кстати, и пример программиста, пишущего по канонам 90х.

Может, по канонам 60-х сразу? Там же структуры данных, и - эти - алгоритмы)))

asaw ★★★★★
()
Ответ на: комментарий от red75prim

Я так понимаю, что вы сделали какую-то другую задачу. Нужно идти по списку задач снова и снова до тех пор, пока они не закончатся. Те задачи, которые завершились, нужно удалять. Если задача не завершилась и нуждается в расщеплении, то в конец списка нужно поставить новую задачу.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Достаточно вызывать эту функцию в цикле. Я пропустил внешний while(!...is_empty()).

red75prim ★★★
()
Ответ на: комментарий от asaw

Перегрузка операторов — синтаксический сахар. Каким боком тут система типов?

anonymous
()
Ответ на: комментарий от asaw

Когда раст научится хотя-бы перегружать операторы, тогда и поговорим про системы типов)

Rust умеет перегружать операторы. Что ты там хотел сказать про систему типов? Говори.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от asaw

Это к перегрузке операторов. А насчет needs_split, наводящий вопрос: что будет если вызвать split(), когда needs_split() == false?

red75prim ★★★
()
Ответ на: комментарий от red75prim

Ничего подобного. Это элемент Command-Query Separation Principle. needs_split — это query, не изменяющий объект. split — это command, модифицирующий объект. Кроме того, для task::split может быть определено предусловие (true == this->needs_split()).

Так что, если беретесь показать аналог, по показывайте его с использованием того же API. А то ведь и исходный пример можно переписать с использованием boost::optional или std::optional (из C++17):

deque< unique_ptr< task > > tasks = get_initial_task_list();
while( !tasks.empty() ) {
  for( auto it = begin(tasks); it != tasks.end(); ) {
    if( it->completed() )
      it = tasks.erase(it);
    else {
      if( auto child = it->split() )
        tasks.emplace_back( move(*child) );
      ++it;
    }
  }
}
Кроме того, в вашем варианте с использованием retain-а внутри цикла количество «пробежек» по списку будет больше, чем в исходном варианте.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Это элемент Command-Query Separation Principle.

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

Стабильного ABI у С++ нет (впрочем как и у Раста), так что использовать тот же интерфейс особого смысла нет.

Можно и кальку с вашего решения сделать, c usize вместо итератора.

https://play.rust-lang.org/?gist=49e1c87c14b49b20a0ee919b37b30efa&version...

red75prim ★★★
()
Ответ на: комментарий от red75prim

У тебя точно так же контракт проверяется во время выполнения if'ом, только ещё и код менее самодокументирован, и нельзя узнать у task needs_split() или !needs_split().

asaw ★★★★★
()
Ответ на: комментарий от asaw

Контракт НЕ проверяется во время выполнения. Во время выполнения проверяется только порождает ли задача новую задачу. Option<Box<Task>> гарантирует, что порожденную задачу можно получить только если она действительно есть.

только ещё и код менее самодокументирован

Сигнатура метода Task::split вполне ясно говорит, что можно получить или не получить новую задачу. Пару методов needs_split и split нужно явно документировать, в частности указывать предусловие для split, которое не будет проконтролировано на этапе компиляции.

Очевидные вещи не видите.

и нельзя узнать у task needs_split() или !needs_split()

В предложенном eao197 коде не было никаких указаний, что needs_split() нужна для чего-то ещё кроме контроля предусловия для split().

Но, никто не мешает добавить needs_split() к трейту Task, и оставить split() как есть.

red75prim ★★★
()
Ответ на: комментарий от eao197

Это элемент Command-Query Separation Principle.

Типичный оопэшный костыль.

Кроме того, для task::split может быть определено предусловие (true == this->needs_split()).

Костыли - такие костыли. Возвращать-то он что в таком случае будет?

А то ведь и исходный пример можно переписать с использованием boost::optional или std::optional (из C++17)

Проблема в том, что никто существующие интерфейсы переписывать не будет, да и часть новых будет по инерции писаться по-старому. А в расте использование ATD для таких целей - уже общепринятая практика.

Esper
()
Ответ на: комментарий от red75prim

Сигнатура метода Task::split вполне ясно говорит, что можно получить или не получить новую задачу. Пару методов needs_split и split нужно явно документировать

А откуда ты, интересно, узнал какова семантика needs_split и split, если тебе об этом никто специально не говорил?)

asaw ★★★★★
()
Ответ на: комментарий от red75prim

Де-факто ABI, разные для разных компиляторов.

CodeSourcery, Compaq, EDG, HP, IBM, Intel, Red Hat, and SGI

Но, лучше чем ничего, согласен.

Люблю такие заявления. Вместо прямого «был неправ, плохо знал матчасть» начинается «лучше, согласен».

tailgunner ★★★★★
()
Ответ на: комментарий от asaw

узнал какова семантика needs_split и split, если тебе об этом никто специально не говорил?

И то правда. Поэтому в С++ я спокойно могу написать:

  auto child_task = task.split();
  child_task.sleep(10);

Ну что за вопросы? Из названий функций и из примера кода приблизительно понятно что они должны делать. Но компилятор об этом не знает.

red75prim ★★★
()
Ответ на: комментарий от red75prim

Ну что за вопросы? Из названий функций и из примера кода приблизительно понятно что они должны делать

Из оригинального то понятно)

asaw ★★★★★
()
Последнее исправление: asaw (всего исправлений: 1)
Ответ на: комментарий от red75prim

Можно и кальку с вашего решения сделать, c usize вместо итератора.

https://play.rust-lang.org/?gist=49e1c87c14b49b20a0ee919b37b30efa&version...

Различия прям кардинальнее некуда :) А уж по уровню безопасности так на порядки... :)))

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

eao197 ★★★★★
()
Ответ на: комментарий от red75prim

Был не прав, есть несколько разных стандартов С++ ABI.

Наверное, я чего-то не знаю, но опубликованный стандарт - один. ABI MSVC++ не опубликован и меняется с версиями компилятора.

Один из них стандартнее других.

MS?

tailgunner ★★★★★
()
Ответ на: комментарий от red75prim

Но компилятор об этом не знает.

Внезапно это не его работа. Это вообще библиотека какая-то реализует свою модель многопоточности. Где-то это std::thread, где-то QThread. При чем тут компилятор? Он должен «покормить собак и ничего не трогать».

i36_zubov
()
Ответ на: комментарий от Esper

Костыли - такие костыли.

Ыксперты такие ыксперты.

Возвращать-то он что в таком случае будет?

Да хоть пустую задачу, которая сразу будет в состоянии completed. Или исключение бросать.

Проблема в том, что никто существующие интерфейсы переписывать не будет

Отучаемся говорить за всех. Кроме того, boost::optional уже давным-давно доступен для использования.

eao197 ★★★★★
()
Ответ на: комментарий от asaw

А откуда ты, интересно, узнал какова семантика needs_split и split, если тебе об этом никто специально не говорил?)

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

i36_zubov
()
Ответ на: комментарий от red75prim

Просили сделать всё то же самое, и хотите чтобы всё получилось по другому?

Вообще-то я просил не вас :)

Но раз вы взялись, то я указал на несколько моментов, которые сильно отличают два наших варианта.

Я бы так сделал: https://play.rust-lang.org/?gist=2d041efba4e6ca55ef35bef7f01b6f64&version...

Ну отличие только в задействовании паттерн-матчинга вместо пары if-ов. Пример-то был призван продемонстрировать то, что используется только интерфейс контейнера, без погружения в потроха, т.е. без нарушения инкапсуляции. Ваше решение здесь в принципе ничем не отличается. Те же самые два вложенных цикла.

И кроме того, метод state, который может сказать, что задача завершилась, а может так же взять и разделить задачу на части (даже когда мы не хотим этого делать по тем или иным причинам) — это, мягко говоря, спорное решение.

eao197 ★★★★★
()
Ответ на: комментарий от asaw

А вот это уже просто откровенное вранье.

«Потому, что так надо» - это не причина. Вернее, причина, но её ценность в деле самодокументирования - околонулевая.

Esper
()
Ответ на: комментарий от eao197

Ыксперты такие ыксперты.

Аргументация - такая аргументация.

И да, насчёт костылей я погорячился, такое может быть удобно в ряде случаев, например, когда у query «говорящее» название или когда command модифицирует объект без возврата значения. Впрочем, в таких случаях ADT тоже не помешают.

Да хоть пустую задачу, которая сразу будет в состоянии completed.

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

Или исключение бросать.

Ещё куда не шло, но тогда кроме заботы о, собственно, проверке needs_split придётся озаботиться ловлей исключения.

Отучаемся говорить за всех.

Видимо, я говорил за тебя, ибо

boost::optional уже давным-давно доступен для использования.

но в твоём сферическом АПИ тасков его и близко нет.

Esper
()
Ответ на: комментарий от eao197

И кроме того, метод state, который может сказать, что задача завершилась...

TaskState явно описывает контракт. Задача может выполнятся, может быть прекращена, может породить новую задачу. Если нужен другой контракт, будет другой интерфейс.

red75prim ★★★
()
Ответ на: комментарий от khrundel

новые проекты предпочитают начинать на других языках

Из последнего: 1. Гугл начал операционку делать, основанную на LK embedded kernel на Си. https://en.wikipedia.org/wiki/Google_Fuchsia 2. Новую интересную ось представили на днях на С++ : http://www.includeos.org/

Более того, популярные и известные проекты на Расте забрасываются своими авторами:

Glium - биндинги в OpenGl. Одна из причин - автор накосячил с проектированием, проще переписать. https://users.rust-lang.org/t/glium-post-mortem/7063/1

Zinc.rs - разработка на Расте под ембед. Среди причин: код стал слишком сложный для поддержки, проблемы с кросс-компиляцией https://users.rust-lang.org/t/zinc-mini-post-mortem/7079

anonymous
()
Ответ на: комментарий от loyd

Менять во время обхода - завязываться на реализацию (ничего не сломается) => нарушение инкапсуляции

А если эта гарантия в документации прописана?

DarkEld3r ★★★★★
()
Ответ на: комментарий от khrundel

Вы можете не верить, но С++ доживает свой век... новые проекты предпочитают начинать на других языках.

Это совершенно точно не так. Правда не знаю хорошо ли это или нет.

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 1)
Ответ на: комментарий от Esper

И да, насчёт костылей я погорячился

Т.е. делать вбросы на счет костылей — это нормально, а в уровне аргументации виноват я. Неплохо так устроились.

но в твоём сферическом АПИ тасков его и близко нет.

А он там и не нужен. Есть needs_split, который, например, говорит, что задача слишком «жирная» и ее можно попробовать порезать на кусочки. И есть split, который задачу на кусочки режет.

Пользователь, если хочет побыстрее обработать жирные задачи, может дергать needs_split. И, если находит жирную и имеет вычислительные ресурсы, то может дернуть split.

Пример с boost/std::optional был показан «для коллекции», мол, не только в Rust-е есть Optional<Box<>>.

eao197 ★★★★★
()
Ответ на: комментарий от red75prim

Этот метод state - вообще порнография какая-то. Либо он сообщает состояние, либо меняет его, причём что именно он сделает неизвестно. Предыдущий вариант со split_if_needed был куда лучше, только назвать его надо было правильно, а не прикидываться, что работаешь с неизмененным интерфейсом.

asaw ★★★★★
()
Ответ на: комментарий от khrundel

Вы можете не верить, но С++ доживает свой век

Настало время офигительных историй.

i36_zubov
()
Ответ на: комментарий от tailgunner

Люблю такие заявления. Вместо прямого «был неправ, плохо знал матчасть» начинается «лучше, согласен».

Так ведь этот стандарт существует параллельно стандарту С++. И комитет может принять такие изменения, которые заставят поломать сложившиеся соглашения. Разве нет?

DarkEld3r ★★★★★
()
Ответ на: комментарий от eao197

в уровне аргументации виноват я

Именно. Я позволил себе излишнюю эмоциональность, но на личности не переходил.

Есть needs_split, который, например, говорит, что задача слишком «жирная» и ее можно попробовать порезать на кусочки.

Почему тогда было не назвать метод, например, too_fat? Сомневаюсь, что тогда возникли бы какие-то вопросы.

Просто в коде вида

if (нужно_сделать()) {
    сделай();
}

подход с query/command выглядит несколько костыльно.

Esper
()
Ответ на: комментарий от Esper

Я позволил себе излишнюю эмоциональность

Вы себе явно хотите позволять больше, чем другим.

Почему тогда было не назвать метод, например, too_fat?

Т.е. разделение на query/command внезапно перестало быть ООП-ным костылем? Претензии уже только к имени query-метода?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Т.е. разделение на query/command внезапно перестало быть ООП-ным костылем?

Когда ты вместо рассказа про безграничную пользу query-методов перешёл на личности, а я снизил толщину до:

«такое может быть удобно в ряде случаев, например, когда у query «говорящее» название или когда command модифицирует объект без возврата значения.»

и

«Просто в коде вида if (нужно_сделать()) сделай(); подход с query/command выглядит несколько костыльно.»

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

Esper
()
Ответ на: комментарий от anonymous

автор накосячил с проектированием, проще переписать.

Ну, если почитать пост мортем, то автор надеялся создать универсальную обёртку, что невозможно, учитывая различия реализаций и косяки драйверов opengl. Пичалька, но rust здесь не причём.

atrus ★★★★★
()
Ответ на: комментарий от eao197

Вы начали раскидывать костыли еще до того, как я успел что-либо сказать в ваш адрес.

Я закончил их раскидывать до того, как ты привёл к ним контраргументы.

Esper
()
Ответ на: комментарий от atrus

Специально для вас цитата:

I think that a partial rewrite would be necessary, in other words start from scratch but
copy-paste code from the old library when possible.

и еще специально для вас

when I started glium (and still today), there was no real reference for how
to design an API. I built an API, then changed my mind and changed it, then changed my mind again.
Each change was justified, but I wouldn't have lost that much time if I knew from the start how to
design things in Rust.

Перевод, специально для вас: «Я бы не потерял кучу времени, если бы сразу знал как проектировать для Раста» и теперь вынужден «начать с нуля, копируя код, где возможно».

Learning curve слишком крута. Нельзя просто сесть и написать, используя опыт из традиционных языков.

anonymous
()
Ответ на: комментарий от anonymous

Learning curve слишком крута.

И это не особо здорово.

DarkEld3r ★★★★★
()
Ответ на: комментарий от anonymous

А ещё там написано: «But I'm generally a perfectionnist person and am very critical of my work». Переводить вам судя по всему не нужно.

Я таких людей знаю. (По себе. :-P) У них всегда такое, код, который написали сегодня, намного лучше того, что был написан вчера. :)

atrus ★★★★★
()
Ответ на: комментарий от anonymous

Новую интересную ось представили на днях на С++

На днях... Ей пару лет уже.

проекты на Расте забрасываются своими авторами

Невероятно. С другими языками такого никогда в истории не происходило.

RazrFalcon ★★★★★
()
Ответ на: комментарий от eao197

Я заметил, что вы так и не смогли ответить на вопросы, которые вам были заданы (into_rust() — скринкасты по Rust. Доступно видео с RustConf 2016. (комментарий)). Но вот херни наговорили изрядно.

Явное 4.2 же. into_rust() — скринкасты по Rust. Доступно видео с RustConf 2016. (комментарий) И вы этот ответ читали, так как вместо разговора по делу пошли жалобы на невозможность модифицировать итерируемый контейнер.

С++ будет доживать свой век не меньше, чем Cobol.

Ну, если для вас Cobol - это пример живого языка, тогда да. Я уже писал, что вакансии по поддержке старого кода на C++ никуда не денутся, не волнуйтесь.

По сравнению с тем, как развивался C++ до 2011-го года, сейчас все просто в шоколаде.

Модули и всякий асинк/авайт тому порукой! Вроде как понимание необходимости модулей уже лет 10 существует, ещё в 11м ждали.

Ну, уж если сравнивать, как мало новых проектов начинают на Rust-е, в сравнении с количеством новых проектов на других языках, то у C++ еще все хорошо.

Ну да, дедушка ещё достаточно силён, чтоб забороть младенца, определённо он в отличной форме.

Я не утверждаю, что C++ добьёт именно раст. Возможно выяснится, что киллер фичи раста нахрен никому не упёрлись и он так и останется вечно развивающимся языком. С++ помрёт от того, что просто устарел. Собственно, Страуструп всё понимает, поэтому на каждом выступлении требует де-факто похоронить C++ 80-90х, а также наследие C и учить народ писать по-новому. Проблема в том, что для реальной работы с старыми проектами на C++ потребуется знание старого C++, так что никуда от всех этих самописных векторов не деться.

Это нормально. Не всем нужно погружаться в околосистемное программирование или middleware.

Торвальдс возражает с одной стороны, а какой-нибудь Пайк с другой.

Ну, если человек остановился в своем развитии, то да. Только вот он не будет конкурентоспособен в этой индустрии. Тут постоянно нужно учиться.

Ну вы вот учитесь, а толку? Для вас признаком современного программирования является использование emplace_back.

Контрпример чего? Где ваш пример, на который вы мне рекомендуете привести контрпример?

Контрпример всего того, на что вы возражаете. Можете уже не беспокоиться, я видел контрпример со списком тасков, он скорее подтверждает что я писал про «современный C++».

khrundel ★★★★
()
Ответ на: комментарий от eao197

Покажите, как это будет выглядеть по канонам 2010-х.

Ну вот посмотрите на свой код. Он не делает ничего полезного, это аналог пустого цикла, подразумевается, что полезная работа делается где-то в других потоках, а этот кусок только следит за списком тасков, но он уже такого размера, что не стыдно в отдельную функцию выносить. В реальности цикл будет не пустым, кроме вариантов «если А, то удалить текущий элемент» и «если Б, то создать новый элемент» будет ещё 2-3 ветки и с элементами будут что-то делать. В итоге получится портянка на пару экранов. И кто-то обязательно этот код начнёт править, добавлять новые ветки, выносить ветки в отдельные функции и т.п.

И настанет момент, когда кому-то потребуется предыдущий элемент и он не особо задумываясь скопирует итератор. Не потому, что он - дурак, а потому что не заметит, что в одной из веток сидит erase текущего элемента, ведь deque - это специальный контейнер, в котором добавляются и удаляются элементы в один из концов и эта операция не ломает итераторы.

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

И где-то в этот момент у программиста рождается мысль, мол, а нафига мне вообще этот дек упёрся? Особой скорости тут не будет: удаление из середины дека немногим лучше удаления из середины вектора. Особой понятности тоже, вот, приходится описывать, что можно и чего нельзя в цикле. В итоге плюнет и перепишет на тупой перенос из одного вектора в другой, где всё понятно, нужно чтоб элемент сохранился - переноси в список для следующей итерации, нужно разбить - добавляй новый в тот же список. За что будет презираем программистами из 90х, ведь каждому понятно, что можно было deque заюзать.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Явное 4.2 же. into_rust() — скринкасты по Rust. Доступно видео с RustConf 2016. (комментарий) И вы этот ответ читали

И ответов там не увидел. В особенности про паники, который могут вылетать откуда угодно.

Контрпример всего того, на что вы возражаете.

Т.е. вы сами не знаете, на что мне нужно привести контрпример. Да вы совсем больны.

Ну вот посмотрите на свой код. Он не делает ничего полезного, это аналог пустого цикла,

Talks are cheap, show me the code! (C)

eao197 ★★★★★
()
Ответ на: комментарий от eao197

И ответов там не увидел. В особенности про паники, который могут вылетать откуда угодно.

facepalm.jpg

Я: в расте ввели вменяемый, контролируемый способ информирования об ошибке, вместо эксепшенов. Теперь новому в проекте человеку труднее зевнуть и не обработать стандартную, ожидаемую ошибку.

Вы: но есть паники. Паника может случиться где угодно.

Я: паники для неожидаемых ошибок. Но если крайне нужно восстанавливаться после паник - вот есть метод.

Вы: мне так и не ответили про паники.

Теперь вопрос: вы вообще какого ответа ждёте? Волшебную пилюлю, которая сделает так, что ошибок вообще никогда не будет? Я утверждаю: эксепшен/паника - это очень плохой способ сообщения об ошибке, он лучше чем errno в том плане, что не позволяет забить и работать дальше, но хуже чем возврат Result<R,E>, так как скрывает возможные ошибки. Софт, основанный на эксепшенах, может обломаться просто потому что новичок, копипастя 2 строчки с загрузкой иконки, не знал, что вот эта функция может завершиться неудачей.

В расте очевидно, что get_icon(...) возвращает резалт и без обработки не компиляется. Если код бездумно копируется из места, где обработка пропущена, то даже там видно try!(get_icon(...)) или get_icon(...).unwrap(), что намекает.

А в языках с непроверяемыми эксепшенами из-за вот этого неправильного вызова проблема проявится только в рантайме, либо упадёт, либо перехватится где-то на внешнем уровне и вежливо сообщит «Операция сохранения не удалась, старый файл наполовину перезаписан, извините.».

Talks are cheap, show me the code!

Какой вам код нужен? Я вроде вполне понятно описал, самое нетривиальное в этом варианте только nextTasks.push_back(std::move(taskPtr)), но для опытного цпп программиста всё это очевидно.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

А давайте вместо вымышленных диалогов посмотрим на то, что было на самом деле:

khrundel> Про исключения в общем-то всё рассказано уже.

eao197> Простите, но ничего не сказано. Про то, что в Rust-е можно использовать АлгТД для возврата ошибок не прибегая к panic-ам, давно известно. Поэтому я просил рассказать, как быть при наличии panic-ов. Они в Rust-е не могут вылететь откуда угодно? Или на них можно просто забить?

khrundel> Ну, значит вам давно известно, что штатные ошибки в расте трудно не обработать и они не вызовут неожиданное падение из-за того, что кто-то просто забыл поймать ошибку. Этого уже достаточно. Но если важны именно паники - тоже в общем-то всё рассказали, либо падаем, либо ставим барьер. Большего как-то и хотеть нельзя.

Это все, что вы соизволили сказать про особенности работы с паниками в Rust-е. Более плотно данную тему мне довелось пообсуждать с RazrFalcon и red75prim, а не с вами.

Какой вам код нужен?

Здесь код.

Здесь вы сказали:

Вот, кстати, и пример программиста, пишущего по канонам 90х.

Здесь я вас попросил показать как будет выглядеть код, написанный по каноном 2010-х.

До сих пор жду от вас этот самый код. По ходу дела red75prim показал, что на «современном» Rust-е будет выглядеть очень похожим образом.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

А давайте вместо вымышленных диалогов посмотрим на то, что было на самом деле:

И? Чем отличается от того, что я описал? У меня складывается впечатление, что вы вообще не паритесь о смысле написанного, вам важно хоть что-то ответить. Я вам уже раз 5 написал, чем именно обработка ошибок в расте лучше - вы это игнорируете и хотите что-то узнать непременно от меня и непременно про паники. И я не могу врубиться, что конкретно.

Это все, что вы соизволили сказать про особенности работы с паниками в Rust-е. Более плотно данную тему мне довелось пообсуждать с RazrFalcon и red75prim, а не с вами.

Не совсем, я вот помню как писал вам про изоляцию паники внутри потока. Но это не важно, вам уже объяснили про ловлю паники другие, зачем мне повторять?

Здесь я вас попросил показать как будет выглядеть код, написанный по каноном 2010-х.

А здесь я вам на пальцах объяснил, почему так писать плохо и как нужно писать по современным стандартам. Что в мысли «перенос из одного вектора в другой» непонятно?

while(!tasks.empty())
{
    for(auto& task: tasks)
    {
        if (task->isComplete())
            continue;
        if (task->needSplitting())
            nextTasks.push_back(task->split());

        nextTasks.push_back(std::move(task));
    }
    tasks.clear();
    std::swap(tasks, nextTasks);
}
Это на моём уровне знания C++, возможно можно и получше через какой-нибудь copy_if. Ну и, опять же, напоминаю, что в реальном коде этот цикл будет работать не по таскам, а по неким данным, которые в этом же цикле и будут обрабатываться, так что в реальности код будет длинее.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Чем отличается от того, что я описал?

Отсутствием хоть какой-нибудь конкретики.

И я не могу врубиться, что конкретно.

Это очевидно. И очевидно почему.

Что в мысли «перенос из одного вектора в другой» непонятно?

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

Но даже если не обращать внимания на такие «мелочи», то что мы видим: те же самые два цикла, те же самые if-ы внутри. В чем современность-то? В расходе дополнительной памяти?

Типа за последние 20 лет изменилось то, что память больше не ресурс?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Чем отличается от того, что я описал?

Отсутствием хоть какой-нибудь конкретики.

И я не могу врубиться, что конкретно.

Это очевидно. И очевидно почему.

Чотаржу. Это надо постараться, пожаловаться на отсутствие конкретики и отказаться конкретизировать.

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

facepalm. Потребление памяти - это просто смешно. Сколько у вас тасков будет? Миллион? Ну ок, на 4-8 мегабайта больше. Только надо помнить, что дек при каждом удалении из произвольного места сдвигает в среднем 1/4 дека. Какова вероятность, что среди миллиона тасков окажется, ну например, 16 завершённых? Нагрузка на память в 4 раза выше на каждую итерацию, получается.

Поведение при выбрасывании эксепшена такое же как у вас: при выходе за пределы скоупа контейнер грохнется вместе со всеми тасками. Этот вариант неприемлем? Тогда давайте сравнивать возможность восстановления. Вот поймали вы эксепшен снаружи цикла и хотите попытаться снова. Что у вас? дек, про который известно, что где-то внутри находится таск в некорректном состоянии, который при следующем вызове точно так же скорее всего кинет исключение. Что есть у меня? 2 вектора, в одном из них первый ненулевой элемент является проблемным. Я бы сказал, возможность восстановления эквивалентна.

В чем современность-то? В расходе дополнительной памяти?

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

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Про паники - вы, похоже, друг друга не понимаете. eao197 говорит что из-за существования паник на расте надо писать exception-safe код, так же как в плюсах, так что сложность остается. Вы же ему говорите что Option лучше чем исключения, потому что он явный, и что паника - неизбежное, но редкое зло.

Как бы оба правы, о чем спор? Или я уже потерял суть?

anonymous
()
Ответ на: комментарий от khrundel

Это надо постараться

Не надо. Вы все делаете сами. Щеки надуваете, сказать ничего не можете, что вам говорят не понимаете.

Ну ок, на 4-8 мегабайта больше.

Ну память же не ресурс, конечно же.

Только надо помнить, что дек при каждом удалении из произвольного места сдвигает в среднем 1/4 дека.

Это вы сейчас про конкретную реализацию deque говорите?

Но даже если и так, то deque легко меняется на list. Тут ведь не это главное, а то, что кто-то обосрался на счет итераций, в которых нельзя менять контейнер.

Тогда давайте сравнивать возможность восстановления.

Давайте. В моем варианте контейнер с тасками вообще не нужно восстанавливать. Про геморр с вашим вариантом можно вообще не упоминать.

Я бы сказал, возможность восстановления эквивалентна.

Да вы тут уже много чего фееричного наговорили. От вас не убудет.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от anonymous

Или я уже потерял суть?

Суть именно в этом. Проблема в том, что про надобность писать exception-safe код Rust-оманы почему-то не понимают.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Не надо. Вы все делаете сами. Щеки надуваете, сказать ничего не можете, что вам говорят не понимаете.

Возможно и не понимаю, только вот я много раз просил вас уточнить, а вы тут же сливаетесь.

Ну память же не ресурс, конечно же.

Ресурс, цельных 8 мегабайт ресурса!

Я уже понял, что свою неправоту вы принципиально не признаёте, будете нести любую чушь, в надежде, что оппоненту надоест.

Это вы сейчас про конкретную реализацию deque говорите?

А ваша программа на каком деке будет крутиться? Абстрактном?

Дек хорошо документирован, список методов и операторов фиксирован и даже прописано, что и как должно работать. Реализацию сильно не поменять, да и не к чему это, ведь в документации чётко прописано, под какие задачи он спроектирован.

Но даже если и так, то deque легко меняется на list.

Вы не пробовали думать перед тем как что-то написать? list реализуется как двусвязный список, т.е. каждая нода хранит кроме данных ещё 2 указателя на предыдущий и следующий элемент. Т.е. хранение миллиона юникптров потребует не 4-8 лишних мегабайт, как у меня, а уже 8-16. Как там вы писали, «память - ресурс»? И это я ещё не посчитал расходы на аллокацию: аллокатор наверняка выравняет блоки в сторону увеличения и, возможно, добавит свои данные, чтоб знать размер блока при освобождении.

Тут ведь не это главное, а то, что кто-то обосрался на счет итераций, в которых нельзя менять контейнер.

Я уже понял, что для вас главное хоть что-то написать против. Проблема в одном: я не писал, что контейнер менять нельзя. Я писал, что rust, используя борроу чекер, запрещает менять контейнер во время итерации, как пример принуждения к порядку действий в API, и то, что хитроумный код (а код, меняющий контейнер во время итерации всегда хитроумный) в наше время не приветствуется.

Давайте. В моем варианте контейнер с тасками вообще не нужно восстанавливать. Про геморр с вашим вариантом можно вообще не упоминать.

И этот человек что-то пишет тут про exception safety. У вас в списке таска, которая при обращении к ней генерирует исключение. И у вас есть необходимость вести этот список тасок, разбивая их, по мере необходимости. Как вы собираетесь продолжать это делать, без восстановления? Снова войдёте в этот цикл? Ну, ок, он добежит до той же таски и снова вылетит с эксепшеном. Всё, что в контейнере после этой таски никогда не удалится и не разобьётся.

Так что если вы такой любитель написания надёжного кода, вам просто необходимо или оборачивать тело цикла в try и там решать, что делать с битой таской, либо как-то передавать итератор на битую таску в точку обработки исключения и, например, удалять её.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Возможно и не понимаю

Не возможно, а точно. Уточнять что-то после попыток выяснить контрпримеры против каких контрпримеров нужно привести — это просто зря тратить время.

Дек хорошо документирован, список методов и операторов фиксирован и даже прописано, что и как должно работать. Реализацию сильно не поменять, да и не к чему это, ведь в документации чётко прописано, под какие задачи он спроектирован.

Ну так прочитайте. В особенности про случаи, когда удаление идет из начала, а добавление в конец.

list реализуется как двусвязный список, т.е. каждая нода хранит кроме данных ещё 2 указателя на предыдущий и следующий элемент.

Именно поэтому изначально использовался deque. Но если бы удаление из середины в нем было бы слишком частым, можно было бы перейти на list, получив при этом дополнительные плюшки.

У вас в списке таска, которая при обращении к ней генерирует исключение.

Ну так у меня хоть понятно в каком списке. У вас — хрен знает где. Плюс второй контейнер на случай исключения вам нужно будет как-то наружу показывать.

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

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Суть именно в этом. Проблема в том, что про надобность писать exception-safe код Rust-оманы почему-то не понимают.

Ну слава богу, разродились. Итак, ваше возражение про паники касалось вон чего оказывается.

Что тут сказать... Вовсе необязательно. Уже писал, но придётся повторить.

И в языках с исключениями и в расте может существовать точка ловли всех эксепшенов. Какой-нибудь внешний try, который просто выводит сообщение об ошибке и пишет что-то в лог, уже не пытаясь ничего восстановить. Тут разницы между языками практически нет.

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

Это, конечно, не освобождает от обязанности писать с учётом возможной неудачи, но если ты видишь try!(...), то ты явно знаешь, что именно вот здесь может произойти ранний выход из функции и возможные проблемы от этого выхода виднее.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Безусловно, и на расте тоже можно писать устойчивый к исключениям код, но не нужно по чисто экономическим соображениям.

Прям индульгенция говнокоду.

eao197 ★★★★★
()
Ответ на: комментарий от khrundel

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

Выше предлагали:

http://contain-rs.github.io/linked-list/linked_list/struct.LinkedList.html

И тут при некорректных аогументах - паника, это ни к чему не обязывает? Норм?

anonymous
()
Ответ на: комментарий от eao197

Ну так прочитайте. В особенности про случаи, когда удаление идет из начала, а добавление в конец.

Чего читать-то? Deque хорошо удаляет с любого конца и хорошо добавляет в любой конец. А если точнее, он при удалении перемещает элементы до или после удаляемого, в зависимости от того, к какому концу этот элемент ближе. О чём я вам и сообщил, когда написал, что при удалении случайного элемента из дека в среднем будет производиться сдвиг 1/4 содержимого дека.

Именно поэтому изначально использовался deque. Но если бы удаление из середины в нем было бы слишком частым, можно было бы перейти на list, получив при этом дополнительные плюшки.

Т.е. про трату «ресурса» вы уже ничего не пишете? По моим прикидкам, раза в 4 больше чем при использовании 2х векторов.

Мой вам совет: не используйте list вообще никогда. Никакие плюшки не оправдают. Эта идея из 60х, когда процессоры были медленными, а память относительно быстрая.

Ну так у меня хоть понятно в каком списке. У вас — хрен знает где. Не могу возразить, учитывая, что у вас один контейнер, действительно, понятно, в каком списке.

У меня, правда, тоже понятно, битая таска будет в списке tasks. И, как я уже писал, найти её просто, на неё указывает первый ненулевой указатель в этом векторе. Впрочем, если вам нужно ещё проще, можно и так: можно вместо вектора использовать стек или тот же deque, при этом итерироваться не надо будет вообще, просто элемент с вершины стека или с начала дека.

Плюс второй контейнер на случай исключения вам нужно будет как-то наружу показывать.

На какую ружу? Вопрос границ инкапсуляции этого списка, если он крутится внутри одной функции - то и создание и восстановление в этой функции и будут сидеть. Если что-то серьёзнее, оба списка будут внутри одного объекта, там же и восстановление.

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

Я вам объясняю старую мудрость: программист на фортране может написать фортрановую программу используя любой язык программирования. Сейчас только поколение сменилось, вместо фортранщиков сидят вот такие сипыпышники и трендят про экономию памяти, хотя сами готовы на std::list перескочить. Сейчас другое время, редактирование «на месте» не приветствуется, а ещё больше не приветствуется код, который не сможет поддерживать первый же попавшийся студент.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Мой вам совет: не используйте list вообще никогда. Никакие плюшки не оправдают. Эта идея из 60х

Ядра Linux и BSD тоже из 60-х?

anonymous
()
Ответ на: комментарий от khrundel

не приветствуется код, который не сможет поддерживать первый же попавшийся студент

Есть код, который и не доверят первому же попавшемуся студенту.

anonymous
()
Ответ на: комментарий от anonymous

И тут при некорректных аогументах - паника, это ни к чему не обязывает? Норм?

Так и выход за границы массива в расте - паника. Передавайте корректные параметры, что тут сказать. Если передали некорректные - значит всё, программа, или по крайней мере текущая задача неработоспособна и завершается.

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Передавайте корректные параметры, что тут сказать

Действительно, как все просто.

anonymous
()
Ответ на: комментарий от anonymous

Ядра Linux и BSD тоже из 60-х?

Им приходится, они же на C. У них нет конструкторов копирования или перемещения, да и реализация linkedlist проще, при отсутствии дженериков легко можно прямо тут писать. Но я сильно удивлюсь, если такие структуры данных используются для большого количества элементов.

khrundel ★★★★
()
Ответ на: комментарий от anonymous

Действительно, как все просто.

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

khrundel ★★★★
()
Ответ на: комментарий от khrundel

Им приходится, они же на C. У них нет конструкторов копирования или перемещения.

Они как раз знают что, куда и зачем пишется и читается. И именное данные и их организация у них на первом месте. И потому и на C++ и на Rust они напишут точно такие структуры данных, пусть это будет и проще и удобнее, но в памяти останется тем же.

anonymous
()
Ответ на: комментарий от khrundel

Deque хорошо удаляет с любого конца и хорошо добавляет в любой конец.

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

Мой вам совет: не используйте list вообще никогда

Понятно. Пожалуй, в разговоре с вами можно ставить жирную точку.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

Действительно, если list хорош для отдельных случаев, то он не должен использоваться вообще никогда. Ну воопще.

eao197 ★★★★★
()
Ответ на: комментарий от khrundel

а ещё больше не приветствуется код, который не сможет поддерживать первый же попавшийся студент.

Боюсь, что это не аргумент за раст, а скорее наоборот.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Так там ведь не совсем традиционные связные списки?..

А чем они нетрадиционные? Обычные интрузивные двусвязные списки.

anonymous
()
Ответ на: комментарий от DarkEld3r

Боюсь, что это не аргумент за раст, а скорее наоборот.

За, он бы мог стать Java (в хорошем смысле) от системного программирования, если бы авторы сделали бы ему синтаксис попривычней для широких масс и не выкинули бы классы.

anonymous
()
Ответ на: комментарий от anonymous

За, он бы мог стать Java (в хорошем смысле) от системного программирования, если бы авторы сделали бы ему синтаксис попривычней для широких масс и не выкинули бы классы.

Неистово плюсую.

eao197 ★★★★★
()
Ответ на: комментарий от anonymous

А чем они нетрадиционные? Обычные интрузивные двусвязные списки.

Именно тем, что интрузивные. Хотя если это изначально подразумевалось, то ладно.

DarkEld3r ★★★★★
()
Ответ на: комментарий от anonymous

За

Ну не знаю, как по мне «первый попавшийся студен» придёт в ужас от «ограничений раста» и не суть важно в какой синтаксис это завернуть.

DarkEld3r ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.