LINUX.ORG.RU

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

 , , , ,


7

5

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

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

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

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

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

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

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

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

★★★★★

Проверено: Shaman007 ()

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

Не забываем про удаление элемента, на который указывает сохранённый итератор.

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

Программа, которая работает правильно, как правило полезнее программы, которая работает быстро.

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

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

То, что исключения сваливают в кучу ошибки вызванные внешними причинами и ошибки программиста.

К сожалению, нет способа запретить делать это и с паниками.

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

*mut Link<T> - это не мутекс. Это указатель без контроля времени жизни.

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

Я в курсе. Вопрос был в другом: если вы не думаете защищать свой контейнер отдельным mutex-ом (т.е. ваш контейнер изначально не thread-safe), то в чем смысл ваших аргументов по поводу: «вам не нужна многопоточность/вы готовы потратить время на тестирование/отладку кода в многопоточном варианте»?

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

Я в курсе lock-free реализаций с помощью compare-and-swap. Про проблемы с корректной реализацией удаления элементов списка, с защитой от double-free, тоже.

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

Тут какое-то недопонимание. Вот вы написали:

Если вам важна каждая наносекунда, задача требует частых вставок/удалений в середину списка или размер элемента данных сопоставим с кэшем первого уровня, вам не нужна многопоточность/вы готовы потратить время на тестирование/отладку кода в многопоточном варианте, то напишите struct Link<T> {data: T; next: *mut Link<T>; prev: *mut Link<T>}, и следите за доступом к данным вручную.

Не понятно, почему вы увязываете реализацию двухсвязного списка с проблемами многопоточности. Могли бы вы раскрыть эту тему? Считаете ли вы, например, что двухсвязный список должен быть thread-safe изначально?

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

с проблемами многопоточности.

А их нет. Компилятор не даст использовать такую структуру в потоке. Нужно реализовывать sync и send. Там тоже можно налажать, но это уже другая история.

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

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

Недавно сталкивался с такой ситуацией (упрощённо): есть два модуля А и Б. А использует Б и оба используют некий утилитарный код, который бросает исключения. В модуле А эти исключения (обосновано) считаются «фатальной проблемой», в модуле Б - в основном, нет, причём это зависит от контекста вызова, а тип исключения будет одинаков - утилитарный код ведь не знает о контексте.

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

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

Пофиксили пропуск вызова деструкторов в случае паники в одном из них.

Интересно. А перехватить такую панику можно или всё равно нет?

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

Я не понимаю, чем это отличается от обработки кодов возврата? В модуле A придется делать что-то вроде:

r = call_utility_stuff();
match(r) {
  some_code => fatal_error();
  ok => next_op();
  _ => return r;
}
А в модуле B:
r = call_utility_stuff();
match(r) {
  ok => next_op();
  _ => return r;
}
Собственно, то же самое будет и с исключениями. Только в A будет try/catch(some_code), а в B — нет.

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

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

Не понимаю что тут непонятного. Проблема с висячими указателями на удаленные элементы списка - общая для однопоточного и многопоточного варианта. Для многопоточного варианта добавляются проблемы с производительностью при использовании мутексов или специфические для lock-free проблемы с переиспользованием памяти аллокаторами, необходимость использовать memory barriers и что-то там ещё.

Так что, если достаточно однопоточного варианта, то лучше использовать его.

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

Проблема с висячими указателями на удаленные элементы списка - общая для однопоточного и многопоточного варианта.

Понятно.

Для многопоточного варианта добавляются проблемы с производительностью при использовании мутексов или специфические для lock-free проблемы с переиспользованием памяти аллокаторами, необходимость использовать memory barriers и что-то там ещё.

Фишка в том, что в изрядном количестве случаев thread-safe контейнеры не нужны. Используются обычные контейнеры. А между нитями разделяются данные, которые включают в себя разные объекты (в том числе и разные контейнеры). И все эти объекты защищаются тем или иным механизмом.

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

Теперь стало понятнее.

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

Молодой человек, вы дурак или свои же ссылки читать не умеете?
Я уже даже не знаю, чем объяснить уровень защитников Rust-а: отсутствием фантазии или мозгов.
Но упоротость фанатов Rust-а и неспособность адекватно посмотреть на свою любимую игрушку

Фу таким быть.

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

Для крупных проектов все равно приходится писать отдельные test-suite, так что тут без разницы.

Отдельные test-suite в расте тоже имеются из коробки. Это, конечно, не «мега киллер фича», но отсутствие необходимости тащить фреймворк для тестирования удобно.

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

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

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

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

и, во-вторых, сравниваете с C++ными enum-ами, а не union-ами.

Растовые enum могут быть и тем и другим:

enum E {
    A = 1,
    B = 100500,
    C = 2,
}

enum U {
    A(i32, f64),
    B{a1: i8, a2: i8},
    C,
}
В первом случае, с возможностью иметь совместимость с сишными enum.

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

Ну тогда и в С++ можно завернуть результат в экзмепляр класса с методами unwrap и unwrap_or и кидать исключение, если что.

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

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

А чем такая «проверка» отличается от непойманного исключения?

Тем, что unwrap надо писать явно (и в идеале осознанно), а об исключении можно забыть случайно.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Вопрос в цене перехода с C++ на Rust. Фанаты Rust-а явно в разы ее преуменьшают.

Что-то я не вижу в теме массовых призывов переписывать все проекты на расте.

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

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

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

Тем, что unwrap надо писать явно (и в идеале осознанно), а об исключении можно забыть случайно.

OMG. НУ ВОТ ТЫ УЖЕ ВСЁ НАПИСАЛ и словил панику/исключение, в чем отличия кроме того, что обработку исключения можно вставить в любое удобное место цепочки вызовов, а с ошибками Rust так в общем случае не получится - придется всё серьёзно рефакторить?

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

А то локальные gcc сам оборачивает в мютексы.

Формально, до «недавнего» (С++11) времени этой гарантии не было.

Глобальных или локальных?

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

В любом случае, в расте ведь нет аналога локальным статическим переменным, так?

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

Где-то я встречал lazy_static!() внутри функции, удивился, но как работает не проверял.

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

А вот что будет с Rust-ом нужно будет посмотреть.

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

С другой стороны, если автор использует ручное управление памятью и вообще «отстал от прогресса», но либа выполняет нужные функции и не сегфолтится/течёт, то так ли это важно? При этом «индикаторы говнокода» в расте сильнее бросаются в глаза, так что отсеивать такие поделки должно быть проще.

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

Я не понимаю, чем это отличается от обработки кодов возврата?

Исключительно наглядностью. То есть, в A можно писать unwrap и это нормально, в B, в большинстве случаев ошибки должны обрабатываться. Собственно, было требование, что B кидает только строго определённые исключения и «в крайнем случае». Вот только оказалось, что следить за этим на ревью нереально: исключения просачивались из утилитарного кода. Ну нельзя по вызову utils::foo понять будет ли исключение. Плюс утилитарный и использующий его код могут меняться независимо. А вот вызовы unwrap будут бросаться в глаза, более того это можно автоматизировать. У нас и так имеются проверки типа определённый код запрещён если рядом нет комментария.

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

И ещё один момент: я сам периодически защищаю исключения, так как хватает случаев когда их использовать удобно. Впрочем, в последнее время, всё-таки склоняюсь к «кодам возврата».

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

Да, перехватывается

Да, я неправильно понял, интересовал вот такой случай:

https://play.rust-lang.org/?gist=0b456bc07b91fa2c2840ae4a81df0375&version...

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

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

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

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

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

За

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

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

Достаточно оставить старый код без развития, и начать делать новые куски на Rust-е.

Мне не понравились именно обобщения. Потому что отлично понимаю, что встраивать в (плюсовую) инфраструктуру раст далеко не всегда имеет смысл. И да, меня можно считать «фанатом раста» о которых ты столь часто негативно отзываешься.

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

а с ошибками Rust так в общем случае не получится - придется всё серьёзно рефакторить?

Это ещё почему? Панику в расте можно точно так же перехватывать.

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

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

Ну нельзя по вызову utils::foo понять будет ли исключение.

Нельзя понять будет ли исключение или нельзя понять, будет ли конкретное исключение?

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

Почему?

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

Где-то я встречал lazy_static!() внутри функции, удивился, но как работает не проверял.

Ага, забавная штука, забыл о ней. Работает через Deref.

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

Нельзя понять будет ли исключение или нельзя понять, будет ли конкретное исключение?

Ни то ни другое: noexcept - всё-таки штука специфическая, как ты сам писал в сегодняшней статье на хабре. Причём, если смотреть тупо на диф на ревью, то в месте вызова и noexcept не будет видно. Или что предлагается?

Почему?

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

Опять же, коллеги жаловались, что в XCode нельзя отфильтровать несколько исключений и ситуация в духе «запустили под дебагером - посмотрели где отвалилось» усложняется, если в процессе бросается (и ловится) много исключений. Впрочем, это скорее проблемы инструментов.

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

Ещё добавлю: стало казаться, что исключения удобны, в первую очередь, для подхода «если где-то упадёт - воткнём catch», то есть, для откладывания проблемы. Ну или для игнорирования уровнем выше.

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

Ни то ни другое

Ну вот для меня не понятно. Если мы знаем, что мы можем сделать в случае возникновения исключения X, то мы оборачиваем код в try/catch(X) и делаем обработку. Если мы не знаем что делать с исключением, но нам нужно как-то восстанавливаться, то используем RAII, но исключения не ловим (ну либо ловим для последующего переброса). И исключения можно ожидать отовсюду. За исключением таких методов, как swap или деструкторы.

Если нам нужно сделать какие-то действия в контексте, где исключения не должны возникать (например, при написании собственного swap), то мы просто выносим эти действия в noexcept-метод.

Главная проблема в том, что если мы написали свой swap, в котором использовали swap из библиотеки X версии 1 и он был noexcept, а потом перешли на версию 2 и там он уже не-noexcept. Здесь бы хотелось каких-то гарантий. Или простых способов записывать подобные контракты в коде самому (вроде бы в C++17 это можно будет делать, т.к. там noexcept входит в сигнатуру функции).

что в XCode нельзя отфильтровать несколько исключений и ситуация в духе «запустили под дебагером - посмотрели где отвалилось» усложняется

А можно подробнее? А то я не могу себе представить о чем речь.

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

Нет, там именно пробежка

Там еще есть http://contain-rs.github.io/linked-list/linked_list/struct.Cursor.html#method... - удаление по итератору (точнее, аналогу итератора). Прохода по списку там нет: https://github.com/contain-rs/linked-list/blob/master/src/lib.rs#L500, так что с удалением всё в порядке.

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

Это ещё почему? Панику в расте можно точно так же перехватывать.

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

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

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

То есть eao197 не указывал?

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

Или что ты этим своим выпадом в мой адрес хотел сказать?

Что твое мнение можно спокойно игнорировать.

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

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

+1

Впрочем, коды возврата (unwrap + catch на панику) тоже удобны для последнего случая :)

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

Что твое мнение можно спокойно игнорировать.

Как и твоё, и вообще любое. Поэтому можешь своё мнение по поводу моего мнения вообще не высказывать.

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

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

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

Вообще, конечно, это показатель как ты стал вести себя в этой дискуссии.

У нас с тобой здесь не было дискуссии.

Это просто позорный слив

Я всё ждал, когда ты его засчитаешь.

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

Что-то никто за день не возразил, что panic = sort of bottom. (Я честно не знаю, так ли это, но вроде похоже) Жаль, а тема интересная.

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

GoodRiddance ()

... и тема вышла в топ на первое место, сместив прежнюю тему про Rust. Что-то не так с этим языком :|

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