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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Даже не знаю стОит поддерживать эту тему или нет... Списки, вообще-то, позволяют их изменять не трогая при этом хранящиеся в них объекты. Во-вторых, если вы гнете пальцы и утверждаете, что раст - не только убийца Си++, но и Си - в первую очередь, то не забывайте, что Си существует для 8-битных микроконтроллеров, где и для ассемблерных-то программ памяти мало. Расту, конечно, не светит такая ширина охвата оборудования, но хотя-бы для галочки можно было бы придумать ответ посерьёзней.

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

https://www.linkedin.com/pulse/performance-array-vs-linked-list-modern-comput...

Извини, но ты и автор этой статейки - клинические идиоты. Ты потому-что не прошел дальше по ссылке и не увидел оригинальную статью, зато принял все за чистую монету. А он потому-что по «Random Insert (+Linear Search)» сделал гениальный вывод. А реальная картина при известном месте вставки вот такая:

http://piccy.info/view3/10375986/057b822563b317b1b3fde4d5727bc5b1/

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

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

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

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

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

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

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

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

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

anonymous
()

1) *Не* дырявая система типов

2) Отсутствие исключений

3) Тьюринг-полнота

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

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

1) *Не* дырявая система типов

Pls elaborate. А то так можно докатиться и до «не решает проблему останова».

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

Это типичная ошибка, которая проявляется как при использовании исключений, так и при использовании кодов возврата. Только почему-то акцент делают на «неявности» исключений.

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

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

И говоря о забытых исключениях я имею в виду случай, когда где-то в глубине второй операции A используется функция B, которая вызывает C, где используется D. Автор D решил, что о неудаче следует сообщать исключением. Когда автор B писал свою функцию ещё не было никакой A, так что если он и знал о возможном исключении из-за D, то он считал, что оно обработается где-то вверху. А потом кто-то написал свою A и он вообще не в курсе, что где-то там есть исключения.

Если коды возврата используются последовательно, то эта ошибка из D будет или обработана, или возвращена наверх. Автор A не сможет забыть, что если пишешь транзакцию, то надо предусмотреть её откат, если что-то ломается на полпути. Теперь ещё представим, что сейчас B не может сломаться и в коде A лепота без отката изменений. Если кто-то изменит D так, что ошибка теперь возможна, то A просто не скомпилируется. Не получится забыть о том, что D непрямо используется в A и туда теперь надо добавить откат транзакции. А добавить выброс исключения в функцию и не проверить, а нет ли болванов среди вызывающих её,— легко.

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

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

Опять вы со своим ООП.

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

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

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

Там есть Cursor.

Я знаю, и сам автор советует писать так:

enum Action {
    Remove,
    SeekForward,
}

loop {
    let action = match cursor.peek_next() {
        Some(t) =>
            if *t as *const T == timer as *const T {
                Action::Remove
            } else {
                Action::SeekForward
            },
        None => break,
    };

    match action {
        Action::Remove => {
            cursor.remove();
            break;
        }
        Action::SeekForward => cursor.seek_forward(1),
    }
}

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

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

Как будто это не так. Одна из самых распространенных ошибок.

Статистику по ошибкам в студию.

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

Ба, что это? Неужели use?

Начинаете сливаться. use != #include. Я могу импортировать одну единственную функцию, если мне нужно.

Тут не только use, тут еще и main.

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

Про то, какова цена этого «теста» можно и не спрашивать.

Вас не смущает, что над этим кодом написано Example, а не Test?

В общем, вы путаете unit-тестирование со всем остальным.

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

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

И отдельно стоит отметить саму идею курсора - это всем костылям костыль.

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

Перелопачивать 100500 статей нет желания.

Зато безосновательно высказывать мнение про распространенность ошибок - есть.

Продолжайте использовать свой «безопасный» С++.

Не продолжайте, а продолжаем. Он останется и с тобой - в компиляторе rust и в дебаггере gdb (вот только на днях перешел). Потому рекомендую расслабиться и выбирать язык под задачу, а не из-за фобий и маний.

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

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

Я так и делаю. Но меня пытаются переубедить.

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

А реальная картина при известном месте вставки вот такая:

И откуда же возьмётся «известное место вставки» без линейного поиска в списке? Про идиотов, делающих N вставок в начало массива и имеющих O(N^2), давайте не будем говорить.

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

use != #include. Я могу импортировать одну единственную функцию, если мне нужно.

Простите, что не в курсе чем конкретно отличается use от include, для меня важен сам факт того, что в документации сделана специальная обвязка для создания значимого для примера контекста.

Это пример из доки модуля, а не метода.

И? Доки по модулям писать не нужно?

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

Вас не смущает, что над этим кодом написано Example, а не Test?

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

В общем, вы путаете unit-тестирование со всем остальным.

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

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

Скажите, пожалуйста, вы долго программировали на языке без исключений (вроде C), а потом пришлось перейти на язык с исключениями?

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

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

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

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

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

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

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

И откуда же возьмётся «известное место вставки» без линейного поиска в списке?

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

Про идиотов, делающих N вставок в начало массива и имеющих O(N^2), давайте не будем говорить.

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

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

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

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

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

За валидностью сохранённого итератора, естественно, должен следить программист. В однопоточном варианте это ещё реально, в многопоточном - желаю удачи.

Сделать интрузивный список на Rc и rc::Weak никто не мешает и в Расте.

Без разницы - в начало или нет [...]

Про кэши процессоров я зря писал? На рабочей нагрузке премущества O(N) над O(N^2), вполне могут потонуть в константных составляющих. Так что рассуждения «это будет двигать память, а это не будет двигать память» без измерения реальной производительности ничего не дают.

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

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

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

«Какие-то специфические условия» - это, как тебе намекнули, объекты размером больше int'a.

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

За валидностью сохранённого итератора, естественно, должен следить программист.

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

В однопоточном варианте это ещё реально, в многопоточном - желаю удачи.

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

Сделать интрузивный список на Rc и rc::Weak никто не мешает и в Расте.

А потом погонять бенчмарками и сделать окончательный вывод, что х%рня эти ваши списки.

без измерения реальной производительности ничего не дают.

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

В остальных случаях Vec или VecDeque будут быстрее

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

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

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

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

Без разницы абсолютно, либо ты следишь за доступом к данным, либо нет.

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

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

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

То есть у нас разработчики раканы

Скорее, «просто люди», со всеми их слабостями, но можно и так сказать, да.

документацию мы в принципе не пишем

Ну да. А если и пишем, то не читаем, а если и читаем, то не полностью. Смотри пункт 1.

Но виноват C++

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

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

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

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

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

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

А разве нет? Atomic и порядок инициализации он уже умеет?

Возможно, мы говорим о разных вещах. Инициализация статических переменных «теперь » (с С++11) «thread safe». С порядком инициализации ничего не менялось.

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

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

Мне вот интересно, вы правда думаете, что в многопоточном коде рулят thread-safe контейнеры с мутексами внутри?

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

подождем, пока к Rust-у не подтянутся толпы индусов, которые начнут лепить на коленках двусвязные списки через unsafe

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

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

За счет чего повышается эффективность кода.

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

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

Способность людей ошибаться не стоит недооценивать. Плюс элементарная глупость, незнание, непонимание и т.д.

Вот, недавно, на одном из ресурсов дали ссылку на какой-то крошечный рендер. Заглядываешь в код. С одной, стороны, вроде бы нормальный C++. С другой ручное управление памятью, зачем-то ручное дергание close, повсеместное использование int-ов для индексации (причем, иногда с явным приведением size_t к int). Ну вот как такое объяснить?

Или, еще из недавнего. Попал на оценку доработок относительно недавно написанный код. В одном из мест разработчик использует шаренные между потоками данные. Только при read-only доступе к ним он mutex не захватывает, а при read-write доступе захватывает (но структуры данных там не такие, чтобы выжить при подобных обращениях). При этом остальной код более чем нормальный.

И такие внезапные помутнения доводилось видеть хоть в C++, хоть в Java, хоть в Ruby. Тут уж точно, если что-то может быть использовано не правильно, оно будет использовано не правильно.

Посему дуракоустойчивость языка — это важная характеристика. C++ здесь сильно проигрывает той же Java. А вот что будет с Rust-ом нужно будет посмотреть.

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