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

Применительно к обеспечению exception safety это не имеет никакого значения.

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

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

ИМХО, это вполне нормально, как часто ты отлавливаешь out_of_range или bad_alloc в С++?

Простите мне мой французский, но я уже запарился на LOR-е объяснять простую вещь: если программировать с оглядкой на exception safety, то без разницы какое именно исключение и откуда вылетает. В программе либо есть места, где можно последствия исключения почистить (начать все заново, отдать отрицательный ответ, предложить сохранить документ под другим именем и т.д.), либо таких мест нет. Если такие места есть, то там, опять же, редко когда нужно знать конкретный тип исключения. Если таких мест нет, все завершится std::terminate и исключение не будет отличаться от Rust-овой паники.

Блин, ну просто же все. Причем так дела обстоят для большого числа языков с исключениями (D, C#, Java, Ruby как минимум).

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

Лучше грохнуть всё остальное.

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

И как вы собираетесь корректно обрабатывать исключение вызванное записью за пределы массива?

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

Паника раскручивает стек, и очищает всё что можно очистить. Что вам ещё надо?

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

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

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

Про то и речь. Написание кода на Rust с учетом panic safety не будет сильно отличаться от написания кода на C++ с учетом exception safety.

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

(начать все заново, отдать отрицательный ответ, предложить сохранить документ под другим именем и т.д.) [...] Если таких мест нет, все завершится std::terminate и исключение не будет отличаться от Rust-овой паники.

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

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

есть места, где можно последствия исключения почистить

В случае out_of_memory - их чистить придется чуть ли не в каждой строке, чтоб не получить неконсистентные данные.

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

По моему опыту — нет. Если только в проекте нет всяких извратов, вроде two phase init. Или кусков кода, которые были написаны в стиле «исключения и RAII — зло, поэтому мы пишем без исключений и все чистим вручную».

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

Про то и речь. Написание кода на Rust с учетом panic safety не будет сильно отличаться от написания кода на C++ с учетом exception safety.

Требования транзакционной безопасности (скажем, отсутствие побочных эффектов, если операция завершилась неудачно) намного сильнее exception safety или panic-safety. Так что Раст тут проще, с учетом того, что в безопасном коде (без unsafe), panic-safety обеспечивается автоматически (невозможно получить неконсистентные данные), в отличии от exception-safety, к соблюдению которого нужно прилагать усилия.

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

Так что Раст тут проще, с учетом того, что в безопасном коде (без unsafe), panic-safety обеспечивается автоматически (невозможно получить неконсистентные данные)

Доказать это утверждение вы чем-нибудь можете?

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

Или кусков кода, которые были написаны в стиле «исключения и RAII — зло, поэтому мы пишем без исключений и все чистим вручную».

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

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

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

Безопасность не значит, что можно писать что угодно и оно будет работать не смотря ни на что. Для Раста безопасность означает: отсутствие memory corruption, отсутствие data races.

«да пусть все и падает».

Да, пусть всё и падает, если это допустимо. Раньше упадёшь, меньше испортишь. Паника - это, блин, не исключение. Это индикатор бага в программе.

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

Доказать это утверждение вы чем-нибудь можете?

Вам формальное математическое доказательство корректности компилятора и soundness of type system? Думаю за несколько сотен миллионов долларов смогу лет через 10 предоставить. Так что пока поищите контрпримеры.

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

И RAII сам по себе магическим образом не откатит тебе изменения, которые уже были сделаны.

Тем не менее, RAII дает простой и дешевый способ для отката этих изменений.

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

Так что пока поищите контрпримеры.

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

Вот что вам не хватает, чтобы представить такую задачу:

struct shared_data {
  vector< int > source_values_;
  vector< float > derived_values_;
};
void update_data(mutex & shared_data_guard, shared_data & data, int new_value) {
  lock_guard<mutex> lock{shared_data_guard};
  data.source_values_.push_back(new_value);
  // Тут может быть исключение.
  const auto derived = calc_derived(data.source_values_);
  // И тут может быть исключение.
  data.derived_values_.push_back(derived);
}
Итак, какие гарантии против написания такого нетранзакционного кода дает Rust?

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

Тем не менее, RAII дает простой и дешевый способ для отката этих изменений.

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

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

Паника переведёт Mutex, с помощью которого шарится data, в состояние poisoned. После этого получить data можно будет только с помощью unsafe кода. Я уже писал про это.

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

В теории

На теорию у меня нет ни мозгов, ни времени.

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

Крайне простой вспомогательный тул: https://github.com/eao197/so-5-5/blob/master/dev/so_5/details/h/rollback_on_e...

Один из примеров его использования: https://github.com/eao197/so-5-5/blob/master/dev/so_5/rt/impl/subscr_storage_...

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

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

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

Ладно. Медленно и печально.

В Расте доступ к шареным между потоками данным можно получить только с помощью Mutex.

Чтобы получить неконсистентные данные, возникшие из-за паники в update_data, нужно этот Mutex захватить в другом потоке, потому что поток, в котором возникла паника, уже размотан и прибит.

Если Mutex был захвачен на момент возникновения паники, он переходит в состояние poisoned.

Поток, попытавшийся получить неконсистентные данные, паникует при попытке залочить poisoned Mutex. Никто неконсистентные данные не получает.

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

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

В Расте нельзя передать отдельно шаренные данные и отдельно мутекс для их блокировки. Мутекс владеет шаренными данными, и получить доступ к ним можно только залочив мутекс. Если это ещё не понятно.

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

Поток, попытавшийся получить неконсистентные данные, паникует при попытке залочить poisoned Mutex. Никто неконсистентные данные не получает.

Блин, ну вы бы хоть сами почитали документацию, на которую ссылку даете. В частности, про Mutex::into_inner.

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

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

Mutex::into_inner

If another user of this mutex panicked while holding the mutex, then this call will return an error instead.

Так объясните, о чём вы толкуете. Реализовать аналог С++-ного update_data с сохранением возможности получения неконсистентных данных на safe Расте невозможно.

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

Молодой человек, вы дурак или свои же ссылки читать не умеете?

To recover from a poisoned mutex:

use std::sync::{Arc, Mutex};
use std::thread;

let lock = Arc::new(Mutex::new(0_u32));
let lock2 = lock.clone();

let _ = thread::spawn(move || -> () {
    // This thread will acquire the mutex first, unwrapping the result of
    // `lock` because the lock has not been poisoned.
    let _guard = lock2.lock().unwrap();

    // This panic while holding the lock (`_guard` is in scope) will poison
    // the mutex.
    panic!();
}).join();

// The lock is poisoned by this point, but the returned result can be
// pattern matched on to return the underlying guard on both branches.
let mut guard = match lock.lock() {
    Ok(guard) => guard,
    Err(poisoned) => poisoned.into_inner(),
};

*guard += 1;

https://doc.rust-lang.org/std/sync/struct.Mutex.html

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

Один из примеров его использования

Что ж, похвально, весьма хороший код. Не часто встретишь такой тщательный подход.

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

В C++03 писать такой код было сложнее. Лямбды и move-semantic очень сильно упростили жизнь за последние лет 5.

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

А вот это уже интересно. into_inner() должен разрушать Mutex, поскольку Mutex не реализует Copy, делая невозможным последующий доступ к нему. Но я сейчас проверил и доступ к нему остаётся. Надо разбираться.

Но, по крайней мере, вы знаете, что имеете дело с потенциально неконсистентными данными.

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

Аргументы из серии, что теорема Пифагора устарела)

Желаю тебе дальнейших успехов в программировании на теореме Пифагора.

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

Аргументы из серии, что теорема Пифагора устарела)

Желаю тебе дальнейших успехов в программировании на теореме Пифагора.

успехов обходиться без математики в программировании)

Вот так сначала Си стал теоремой Пифагора, а потом к теореме Пифагора свелась математика. Жги еще.

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

Вот так сначала Си стал теоремой Пифагора, а потом к теореме Пифагора свелась математика. Жги еще.

Си стал теоремой Пифагора только в твоей голове.

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

Забавно, что по второму пункту у тебя возражений нет.

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

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

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

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

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

Где-то в сорцах std - да, но там всё протестировано и не нужно каждый раз изобретать велосипед.

RazrFalcon ★★★★★
()
Ответ на: комментарий от 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 ★★★★
()
Ответ на: комментарий от i36_zubov

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

Этот кот(C++) очень жирный, как на фотках в сети. И никто не хочет этого кота привести в нормальный вид.

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

Эм, так в чём здесь проблема-то? into_inner() и компания у PoisonError специально предназначены для случая ручной обработки poisoned мьютексов.

poisoned.into_inner() нельзя случайно вызвать и случайно использовать данные. Они явно говорят, что программист в курсе, что данные под этим мьютексом возможно неконсистентны из-за пролетевшей паники (но они там есть, memory safety на месте). Пока обрабатывается PoisonError, мьютекс нельзя ещё раз захватить и получить ещё одну ссылку на данные (data race safety на месте).

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

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

Это другой into_inner(), вот этот у PoisonError. Он разрушает не мьютекс, а конкретный LockResult. При следующем доступе ко мьютексу lock() всё так же вернёт Err.

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

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

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

Но тутошние растоманы не могут понять, что в такой ситуации их любимый Rust ничем не лучше охаемого ими C++.

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

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

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

Ваша предвзятость не имеет границ.

Вы сравниваете общие фичи раста и плюсов и находите недостатки. Тут всё понятно. Но почему вы тактично пропускаете все преимущества раста перед плюсами: модули, cargo, pattern matching, lifetimes, borrow checking, поддержка тестирования и документации из коробки, нормальные enum'ы, строки и прочее-прочее?

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

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

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

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

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

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

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

Здесь код.

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

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

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

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

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

Ну, как бы, Rust и не обещает автомагического отсутствия дедлоков и логических ошибок.

Позволю себе напомнить, с чего все началось: некий хрюндель сделал перечень проблем C++, от которых якобы Rust спасает разработчика. Для меня было очевидно, что по двум пунктам это явно не так. О чем и пытался поговорить.

Но упоротость фанатов Rust-а и неспособность адекватно посмотреть на свою любимую игрушку превратило это в нехилой мощности срач.

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

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

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

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

модули,

Модули сами по себе не есть какое-то большое достоинство. Если за модулями прячется увеличение скорости компиляции до уровня таковой в D и Go, вот тогда это серьезное преимущество.

cargo,

У меня есть простой и удобный способ подтаскивать внешние зависимости в C++ проект, так что не сильно большое преимущество.

pattern matching,

Это большой плюс.

lifetimes, borrow checking,

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

поддержка тестирования

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

и документации из коробки,

Проблема с документацией не в том, каким инструментом ее из исходников доставать. А в том, чтобы ее в исходниках написать. Так что Doxygen пока вполне справляется.

нормальные enum'ы,

Не очень понимаю о чем речь.

строки и прочее-прочее?

Мне хватает std::string, но у меня задачи не связаны с обработкой текстов и/или i18n.

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

Модули сами по себе не есть какое-то большое достоинство.

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

Так что Doxygen пока вполне справляется.

Он умеет компилировать и запускать примеры из доки?

Для мелкий утилит написать тест прямо в коде бывает удобно

Это удобно для unit-тестов как таковых.

Не очень понимаю о чем речь.

Разница между плюсовыми enum'ами и растовыми огромна.

Мне хватает std::string

О того, что вам хватает, они не перестают быть чуть менее чем полностью убогими.

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

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

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

Он умеет компилировать и запускать примеры из доки?

Это еще зачем?

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

У меня нет претензий к Rust-у.

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

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