company_banner
6 сентября 2014 в 15:07

Rust: как код может быть одновременно быстрым и безопасным. Рассказ Степана Кольцова в Яндексе

Привет. Меня зовут Степан Кольцов. Недавно я выступал на Java Party в киевском офисе Яндекса с докладом про язык Rust, который несёт в себе очень много для будущего программирования. Некоторые коллеги утверждают, что я всегда говорю про Rust, когда у меня есть такая возможность. Сегодня я хочу поделиться этим рассказом с вами и объяснить, почему мне это кажется важным.



Для начала пара слов о том, что такое Rust. Последние 15 лет между разработчиками на Java и на C++ ведётся спор о том, какой язык программирования хуже — Java или C++. Программы на C++ глючат, падают, и в них утекает память. Программы на Java тормозят и требуют слишком много памяти.

Rust — новый современный язык программирования, разрабатываемый компанией Mozilla — решает проблемы Java и C++: программы, написанные на Rust, одновременно быстрые и безопасные. Rust является таким же низкоуровневым (в смысле close-to-metal) языком программирования, как и C++, однако в язык встроены конструкции, позволяющие на этапе компиляции доказывать, что в программе не случатся ошибки работы с памятью, как то обращение после использования, двойное удаление, использование неинициализированной памяти и т.п. В Rust для этого используется механизм borrowed pointers. Большая часть моего рассказа была посвящена описанию этого механизма.

Кроме того, Rust исправляет многие ошибки, допущенные при проектировании C++ и Java. Например, шаблоны в Rust, в отличие от C++, статически типизированы, а вместо дженериков Java используется механизм, похожий на тайпклассы Haskell.
 
В данный момент язык программирования Rust ещё не начал использоваться в промышленном программировании, и найти работу программистом на Rust прямо завтра, скорее всего, не получится. Однако изучать Rust стоит — чтобы лучше программировать на Java и C++ и чтобы понимать, в каком направлении развивается современное программирование.

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

Я пристально слежу за тем, что происходит в мире Rust, и представляю, что там вообще сейчас происходит. Когда я впервые познакомился с этим языком, у меня появилось ощущение, что я был слеп, но вдруг прозрел. Раньше я был уверен, что программисту представляется бинарный выбор: либо программа пишется на C++, работает быстро и падает, либо программа пишется на Java, работает безопасно, но медленно. Оказалось, что есть еще другие подходы: программа может быть одновременно быстрой и безопасной. Почти весь мой рассказ посвящен тому, как устроена работа с памятью в Rust, ведь работа с памятью — это главная проблема С++.

Java считается безопасной средой, но при этом у программ на Java большой оверхед по памяти и CPU. Кроме того, Java не позволяет безопасно писать многопоточные программы. Java никак не гарантирует, что если объект предназначен для работы из одного потока, то его не получится использовать в разных потоках. В Rust такой проблемы нет. Java не гарантирует, что вы не забудете поставить mutex.

План рассказа рассказа (на видео):
  • Примеры кода;
  • Основные типы данных;
  • Про то, что перемещение объектов сделано лучше, чем в C++11;
  • Указатели;
  • Как падают программы на C++, и как такие же программы на Rust не падают;
  • Время жизни объектов в языке Rust;
  • Запрет алиасинга в Rust, и какие проблемы этот запрет решает;
  • Как в Rust сделан mutex.
     
Автор: @stepancheg
Яндекс
рейтинг 635,54
Как мы делаем Яндекс

Комментарии (128)

  • +2
    Очень интересно, но очень тихо.
    • +7
      Вроде нормально.
    • 0
      Если винда, то в микшере есть отдельный ползунок громкости для браузера. В свое время решил так проблему тихих сериалов при онлайн-просмотре в хроме.
  • +5
    Спасибо за интересный рассказ!

    Заинтересовала фраза
    Например, шаблоны в Rust, в отличие от C++, статически типизированы...

    Поясните пожалуйста, что имелось в виду.
    • +4
      В Rust при использовании объектов generic типов вы можете запрашивать лишь те методы, которые прописаны в тайпклассе (можно считать это интерфейсом, можно провести аналогию с концептами Си++17).
      • +1
        Спасибо! Не мог понять, чего же не статического в шаблонах C++ :)
      • +2
        Я не знаком с синтаксисом на память, но можно привести такой пример:
        fn toString(t: T) { t.toString() }
        fn toString<T: ToStringTrait>(t: T) t.toString() }

        Первый вариант не скомпилируется, второй скомпилируется если ToStringTrait имеет метод toString.
  • +13
    Огромное спасибо за видео. На 14й минуте прям пустил скупую мужскую слезу. 10 лет с С++ и каждый раз какой-то программист сделает что-то такое, а потом все рушится. Чувствовал себя
    вот так (gif)
    image
  • +6
    Здесь ваше видео выложено с ссылкой на видео 1,3 ГБ
    И добавлено презентация на slideshare.net. Было бы неплохо добавить это в статью.
  • +12
    Пользуясь случаем хочу поблагодарить Яндекс за то что выкладываете в открыты доступ свои внутренние конференции. Всегда с огромным интересом смотрю записи. Особенно C++ секцию.
  • НЛО прилетело и опубликовало эту надпись здесь
    • +31
      Закопайте стюардессу.
    • 0
      А еще он реально развивается и перспективный.
      • НЛО прилетело и опубликовало эту надпись здесь
  • +3
    Спасибо за доклад!
    Возможности языка выглядят впечатляюще относительно классических подходов к статическому анализу того же C++.

    Действительно ли в разработке часто используется Mutex и как он реализован внутри? На первый взгляд кажется, что это весьма дорогое удовольствие — вешать явные локи на каждую переменную.
    • +1
      Дороги не локи, а lock contention. А можете привести примеры, где вы слышали об использовании локов?
      • 0
        В статьях о Lock-free программировании весьма часто говорят о плохой масштабируемости пессимистичных схем блокировок. Конкретно в Расте я как раз и хочу узнать, чем является Mutex внутри и каковы стратегии по работе с ним.

        Пример из мира С++: начиная с последних версий Qt4 мьютексы используют оптимистичные алгоритмы на атомарных переменных.
        • +1
          Mutex внутри Rust точно такой же, как и в любой другой современной среде программирования. Точно так же там захват без contention делается через атомики.
    • +1
      Не очень понял вопросы.

      Mutex обычно используется там, где его нельзя не использовать. Если несколько потоков должны обращаться к общему ресурсу, или если потокам надо спать ожидая какие-то условия, то без мьютексов (или каких-то подобных механизмов) обычно никуда не деться. На каждую переменную Mutex не вешаетcя. Mutex может закрывать сложную структуру, например, хеш-таблицу.
      • 0
        Тут скорее идеологическая разница — в том же boost.asio рекомендуют защищать не данные, а сами операции посредством strand. Думается, это обеспечивает определенную свободу реализации этих механизмов под капотом, ну и повышает уровень абстракции.
        • 0
          Не знаю, как реализован strand, но 99%, что где-то внутри него всё равно есть mutex.
  • –18
    Если волнуют утечки памяти в C++, есть профилировщик памяти Valgrind. Из функции C++ можно вернуть объект обернув его умным указателем со счётчиком. Если программа на C++ падает, начните тестировать свой код, хотя бы TDD. Лично я считаю Qt Creator лучше, чем Visual Studio для работы c C++ вне зависимости используется ли Qt или нет. Чудес не бывает, можно сколько угодно менять язык, но лучше от этого программы не станут, так как дело не в языке, а в программисте. Начните использовать Rust и быстро окажетесь в аутсайдерах. Самые быстрые программы, в том числе и поисковые машины написаны на C++. Ничего не даётся даром, С++ даёт полный контроль над памятью, взамен требует квалифицированного обращения. Java между тем это хорошая виртуальная машина. C/C++ и Java это два топовых языка с максимальной востребованностью. Рассуждать о том какой из них хуже подобно рассуждению о том, что хуже, золото или платина. Ну прям не знают даже.
    • +2
      Видео не про утечки, а про другие проблемы (вроде dangling pointers для C++ и недетерминизм для java). Скажете: «Если у вас проблемы с UB, не пишите код, вызывающий UB!»?
    • +9
      На примере Rust мы видим, что C++ мог бы дать более сильные статические гарантии со стороны системы типов, если бы при его создании и развитии имелся сегодняшний опыт.
      • +1
        Более того, принципиально возможно в современный C++ добавить такой же механиз lifetime, какой есть в Rust.

        Однако, я сомневаюсь, что разработчики языка C++ это сделают. До сих пор они добавляли в язык и стандарт не самые нужные фичи.
      • 0
        Если бы при его создании не стояла задача воспроизвести при помощи объектов поведение системы типов языка C. Опыт ту ни при чём.
    • +5
      Если программа на C++ падает, начните тестировать свой код, хотя бы TDD.

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

      Мне кажется, статическая типизация нужна: она делает код более понятным, читаемым, поддерживаемым и т. п. А Rust ещё более типизированный язык программирования, чем C++.

      Ничего не даётся даром, С++ даёт полный контроль над памятью, взамен требует квалифицированного обращения

      Мой поинт в том, что Rust позволяет писать программы такие же быстрые, как и C++, но при этом освобождает голову программиста от ненужных знаний о том, кто владеет памятью.
    • +2
      А вы программируя никогда не делаете ошибок? Мне кажется все ошибаются, и что бы это как-то компенсировать и нужны безопасные средства программирования вроде статического анализа. И очевидно программы таки становятся лучше, если исчезает сразу целый класс ошибок. Например если в языке нет null, то никаких null pointer exception случиться не может. А если null есть, то какой бы программист не был прокаченный, он рано или поздно забудет проверить на null и будет баг. Конечно проблема качества решаются с двух сторон, и программистом, и анализаторами. Но анализаторы практически не ошибаются, в отличии от человека.
    • +14
      Rust — это как раз о том, что можно иметь тот самый zero overhead как в плюсах, но со значительно более вменяемыми гарантиями безопасности. Вы вообще приведенное смотрели/читали?
  • +2
    Спасибо, интересно. Долго не мог въехать в lifetime в Rust, теперь более-менее понятно. Перечитаю документацию при возможности. Перспективный язык, ждём версии 1.0. Радуют талантливо подобранные фичи: Mutex, move и unmutable по умолчанию, smart pointers, RAII.
    • +2
      Насчёт версии 1.0, моё мнение такое: релиз языка состоится раньше, чем язык будет пригоден к промышленному использованию.

      В Rust очень не хватает IDE, и авторы Rust разработкой IDE, насколько мне известно, не занимаются.
      • +3
        Если язык очень активно пойдет в продакшен и массы, возможно JetBrains сделают очередную крутую IDE для него.
        По крайней мере я надеюсь на это >_>
      • +3
        Есть огромное количество языков, в том числе с очень ценными свойствами, для которых нет IDE.
        Существование качественной IDE а ля IntelliJ IDEA для Java — скорее исключение из правила, чем правило. И язык сначала становится массовым, а потом для него пишут IDE, а не наоборот (разве что Kotlin имеет некоторые шансы стать примером обратной последовательности), просто иначе это нерентабельно. Смотрите сами, по данным openhub даже community версия IntelliJ IDEA — это 4.44 млрд. строк кода. А весь проект Rust — 343 тыс. строк кода, что почти в 13 раз меньше.
        Вы всерьёз предлагаете разработчикам Rust почти в 14 раз увеличить объем выполняемой работы? Так мы релиза собственно языка не дождёмся никогда.
        • 0
          IntelliJ IDEA CE — это платформа + Java плагин. И не только Java.

          Сам плагин занимает порядка 13 мб в скомпиленом виде. Python занимает при этом до 5 мб.

          Писать можно и не только самим разрабам. А людям которым язык интересен.
        • +2
          Вы всерьёз предлагаете разработчикам Rust почти в 14 раз увеличить объем выполняемой работы? Так мы релиза собственно языка не дождёмся никогда.


          Не обязательно в первой версии IDE делать все эти прекрасные фичи, которые есть в IDE для Java. Можно начать с навигации и простенького комплишена, а поддержку рефакторинга, отладчика и всяких интеншнов сделать потом.
        • +1
          только не млрд, а млн
      • 0
        Если IDE сводится к генерации типового кода, то Rust достаточно высокоуровневый, что бы типового кода, пригодного к генерации по кнопке, было мало.
        Более полезная функция IDE — поддержка рефакторинга. Здесь может и правда придется долго ждать, пока появится достаточный опыт рефакторинга именно Rust-программ.
  • +3
    Забавный доклад, раньше на Rust не обращал внимания, заинтриговало
    • +6
      Спасибо, значит я добился своей цели.
  • +1
    Степан, а не могли бы вы сделать сравнение Rust vs Go Lang?
    • +14
      Очень кратко так: Go — это замена Java, а не замена C++. По моему мнению, вопреки мнению людей в интернетах, Go не является аналогом Rust.

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

      Там, где надо в процессе выделять 50 Гб памяти, где важна реалтаймовость, и где нельзя потерять 20% памяти на служебные нужды, Go работать не будет. А Rust — будет.
      • +4
        И еще вес рантайма — растовский подойдет для всякого эмбеддеда.
      • +3
        Мне почему-то казалось, что Go это замена python. Вон даже такая же палестина с зависимостями как в python'e.
      • 0
        Может наиболее близкий аналог — это Ada? Интересно было бы их сравнить.
      • +1
        Go — это скорее шаг назад по сравнению с Java, чем шаг вперед.
        • 0
          Главное достоинство Go в том, что hello world работает за одну миллисекунду, а не за одну секунду.
          • 0
            В Java этого тоже можно достичь, если использовать AOT компилятор
            • 0
              Это на практике работает?
              • –1
                Да, Excelsior JET, например, используют дохрена контор.
                • 0
                  Коммерческая основа этого софта существенно снижает область её применения, к сожалению.
              • 0
                Я очень долек от JAVA, но может тут скорее пример ART подойдет. Хотя это и совсем отдельная ветка языка, но может и для остальных сфер кроме Android какая польза выйдет.
        • –1
          Можешь вкратце объяснить это человеку, знакомому с Go, но не с Java? Seriously.
          • –2
            Да Go хуже во всём, начиная от убогого неэкспрессивного синтаксиса (даже в Java лучше) и заканчивая ничтожно маленьким количеством библиотек и стабильностью работы (в Java угроханы миллионы часов QA).
            • 0
              >>стабильностью работы
              Пример нестабильности Go можете привести?
              • –2
                Т.е. со всем остальным вы согласны?
                • 0
                  Вы высказали мысль что Go нестабилен, возникла мысль «А где?». Вот и прошу вас привести примеры. Причем тут «остальное»? Приведите пример!
                  • –6
                    Говорить об абсолютной нестабильности глупо, баги есть везде. Об этом есть смысл говорить только в сравнении с другими платформами. Мне кажется, ни у кого не вызовет сомнения, что стабильность Java выше — это просто следует из того факта, что в Go вложено намного меньше денег и QA (инженеры Sun/Oracle + миллионы программистов), чем в Java.
                    • +1
                      Вы кажется меня не слышите или просто не хотите слышать.
                      >>Еще раз Вашу мысль: «Да Go хуже во… и стабильностью работы»
                      Что бы так утверждать человек должен был:

                      1) Либо Написать набор из тестовых сценариев и проверить каждый для Java и для Go. На основании этого сделать вывод
                      2) Либо почитать отчет о сравнении на основании тестирования от кого-либо. К примеру кто-то в интернет мог выложить
                      3) Либо же на основании своего программерского опыта при реализации чего-либо на Go столкнуться с багой, перепроверить в Java и сделать выводы. Это вариант п.1.

                      Я к тому что утверждая надо прикладывать действительные факты для того, чтобы любой мог взять указанную Вами версию Golang, Java и проверить Ваши слова самостоятельно. Тогда это будет действительным утверждением, которому действительно можно доверять.
                      • –5
                        Я прекращаю этот разговор, так как вы не понимаете, что не конкретными примерами багов определяется стабильность платформы, а количеством часов, вложенных в её тестирование.
                        • +1
                          Вы немного нервный. Успокойтесь. Вам ничего страшного не сделали, а просто попросили аргументировать Ваши же слова! Аргументировать так, чтобы вопросов более не возникало. Я не спорю против мысли что Go хуже или лучше Java. Я всего лишь прошу реальный, конкретный пример отчета или другого документа или хотя бы нескольких кейсов.

                          Вы говорите про кол-во часов вложенных. Это уверяю Вас как раз-таки не показатель!!! Ежедневно тестирую на протяжении нескольких лет и уверяю Вас любой вменяемый разработчик не будет верить количеству часов. Это чисто субъективный показатель. А верят отчетам полученных в ходе тестирования на основании списка тест-сценариев.
                          Не важно сколько билдов пережил код. Важно лишь то что после модификации может быть внесена ошибка и только повторная проверка будет говорить есть ли в том или ином аспекте ошибка или нет.

                          Еще раз: только реальный документ отражающий факт проверки конкретного билда по конкретному списку тест-сценариев! Не кол-во! Только отчет!

                          P.S.:
                          Если Вы думаете что это я Вам минусы к комментариям делаю, то Вы ошибаетесь. Вообще никого не минусую. Это к тому, что мне кто-то создал минус в карму и если это Вы, а я так думать не хочу, то Вы очень сильно не правы.
                          • –2
                            Не важно сколько билдов пережил код. Важно лишь то что после модификации может быть внесена ошибка и только повторная проверка будет говорить есть ли в том или ином аспекте ошибка или нет.

                            И вы думаете, что после каждого билда джаву тестируют с нуля, руками?!
    • +9
      Мне кажется, интереснее Rust vs D. Go не претендует на звание системного ЯП.
      • +9
        D хоть и претендует, но идеологически он имхо ближе к Go. В частности, тем, что в нем есть GC (да, теоретически, его можно отключить — но на практике, на него завязана стандартная библиотека).

        Rust — это именно что попытка сделать современный C++ с нуля — по-прежнему максимально близко к железу, никаких там GC, но safe by default.
        • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          На Go до уровня железа не опустишься, в отличие от D.
  • –8
    Среди безопасных «убийц C++» Go больше признаков жизни подаёт
    • +2
      нет, там система типов так себе
      • 0
        Как вам будет угодно
      • 0
        Go — не убийца C++. Я ответил в соседнем треде, посмотрите.
  • +3
    stepancheg
    Вам же что-то должно не нравиться в Rust. Очень хочется услышать про Ваш опыт подробнее. С чем Вам приходится мириться.
    • +12
      Я когда-то как раз практически по мотивам пропаганды Стёпы попробовал покоммитить в живой проект и делился во внутренних обсуждениях впечатлениями в жанре «поток сознания». Возможно, Вам будет интересно:
      Неоднократно воспетые лайфтаймы и референсы. Это прикольно, но очень непривычно. Реально приходится что-то перестраивать в мозгах, чтобы нормально это воспринимать. Сначала кажется, что «ну, всё просто, есть owned pointer, есть мутабельная ссылка, есть иммутабельная, я про всё это читал, всё просто». Потом оказывается, что есть мутабельные строки вида String и иммутабельные вида &str, которые суть всем знакомый StringView. Потом ты начинаешь их складывать в массив и понимаешь, что массивов бывает тоже два вида — мутабельный вектор Vec и лёгкий слайс вида &[T]. При этом, решив в какой-то момент использовать где-то для простоты слайс, выясняешь, что пустых слайсов не бывает. Может, я их так и не нашёл, не знаю. Но нельзя просто так взять и написать возвращающую слайс функцию, если в какой-то из её веток ты хочешь вернуть пустой список.

      С указателями всё тоже не так легко, как хотелось бы. В какой-то момент мне потребовалось оперировать не конкретными типами, а интерфейсами (trait в расте). Их совершенно закономерно нужно, как и в C++, хранить исключительно в виде указателей — Box, где Box — аналог std::unique_ptr. И вот в этом месте лично я проклял всё, потому что обнаружил синтаксис, весьма схожий со всякими const char const *, только более запутанный. Если вы хотите принимать в своей функции, скажем, Box (который, напоминаю, сам по себе умный указатель), вы можете написать:

      fn fun(dgst: Box<Digest>) // immutable owned variable
      fn fun(dgst: &Box<Digest>) // immutable reference to variable
      fn fun(dgst: &mut Box<Digest>) // mutable reference to variable
      fn fun(mut dgst: Box<Digest>) // mutable owned variable
      fn fun(mut dgst: &Box<Digest>) // mutable variable with immutable reference
      fn fun(mut dgst: &mut Box<Digest>) // mutable variable with mutable reference


      Но это я сейчас такой умный, а поначалу я без всякой задней мысли заиспользовал первый вариант и, будучи уверенным, что я сделал move данных в свою функцию и могу дальше делать с ними всё, что душа пожелает, попытался передать mut-ссылку на этот указатель дальше. А оказалось, что хрен. Целый час убитого выходного открыл мне, что хоть я в этой функции и единоличный обладатель данных, это всё равно не значит, что они мутабельны — мутабельную ссылку на них взять нельзя. Я конечно сам виноват, но это очень большая разница с C++, где наоборот, надо специально говорить const для неизменяемости. Функциональным задротам будет проще, у них в языках обычно тоже всё иммутабельно по умолчанию, как в расте.

      Зато сами trait'ы офигенны. Это вот очень круто, что можно придать любому типу желаемую функциональность, не редактируя сам тип. По большому счёту это работает, как всякие визиторы с перегрузками из C++, только намного читаемее и удобнее в написании и использовании. Ну и концепты, так и не попавшие в плюсовый стандарт, есть из коробки.

      Есть всякая удобная информация, предоставляемая компилятором, которая удобнее и понятнее, чем традиционные ifdef'ы:

      #[cfg(target_os = "linux")]
      fn myfun() {
        ... 
      }
      #[cfg(target_os = "macos")]
      fn myfun() {
        ...
      }


      С другой стороны что-то пока прямо просит его поюзать, но пока недоступно: заголовок, идентифицирующий при компиляции библиотеку и её версию, — #![crate_id = «chroot#1.0.0»] — достать из кода нельзя, информацию приходится дублировать.

      Взаимодействие с сишными функциями не так удобно, как было обещано. Нет, FFI есть и с ним всё хорошо (а функции libc по умолчанию прокинуты в стандартную библиотеку в забавном виде: libc::funcs::posix88::unistd::execvp), но при этом строки в Rust хранятся без \0, что несколько огорчает libc. Несмотря на то, что метод преобразовании строки строки существует, это, во-первых, явно вызывает реаллокацию памяти, а во-вторых, чтобы передать строку из argv (который имеет тип Vec) в libc-функцию, надо написать вот так:

      argv.get(1).as_slice().to_c_str().unwrap() // Vec<String> -> String -> &str -> CString -> *c_char
      • +2
        >>Возможно, Вам будет интересно:
        Очень даже интересно! Спасибо огромное.
      • +1
        argv.get(1).as_slice().to_c_str().unwrap()

        И да здравствует утечка!
        Уже второй пост с вот этим в каментах.
        Предвижу, что это будет самая известная ошибка новичков в расте.
        • 0
          Освобождать память надо отдельно, да.
          В моём случае строка раскручивалась для передачи в exec(), поэтому об утечке речи не шло :)
          • +2
            В любом случае, кошерно использовать with_c_str, кажется так это называется (по крайней мере, месяц назад, с растом никогда не знаешь).
        • 0
          Тут действительно утечка. Однако такой код можно написать только с использованием ключевого слова unsafe.
          • +2
            Если проект — не ядро линукс, с очень жестким ревью изменений, то скорее всего такого кода в репозитории будет навалом. А что — компилятор сказал, нужно добавить ансэйф, ну я добавил!
            В Расте есть проблема мальчика и волков: там куча всего требует unsafe, после сотой жалобы компилятора никто и не подумает, что это реально ансэйф.
            • +2
              Тот, кто не подумает, зачем компилятор требует написать unsafe, пусть продолжает писать на Java. Остальным людям разделение на safe/unsafe очень помогает писать надёжный код.
    • +4
      Длинный текст напишу как-нибудь, а если краткто, то многие вещи в Rust мне действительно не нравятся. Например, мне далеко не всегда нравится направление, в котором развивается язык, часто делают хуже, чем было. Вот, например, недавно в Rust реализовали фичу, которая называется lifetime elision (лайфтаймы остаются, но писать их теперь можно в пять раз реже). КМК, это вредная фича, которая ухудшает читаемость кода.

      Однако все эти вещи, которые мне не нравятся, незначительны по сравнению с хорошими фичами языка.
      • +1
        Вот, например, недавно в Rust реализовали фичу, которая называется lifetime elision (лайфтаймы остаются, но писать их теперь можно в пять раз реже). КМК, это вредная фича, которая ухудшает читаемость кода.


        Другой пример в поддержку. До тех пор, пока мне не пришлось много читать (именно читать) код на функциональном языке, я верил, что фича «вам не нужно явно указывать типы значений, в том числе функций, в том числе объявлений верхнего уровня» — штука полезная, де, писать меньше. На практике оказалось, что как и любую возможность, её нужно использовать экономно и с умом. Иначе читать код становится сильно сложнее: не видно совершенно, как устроены данные, с которыми он работает. Ситуацию усугубляет тот факт, что функциональный код трактует как данные более-менее все, в том числе функции, а в некоторых языках даже модули.
        • +1
          Для выяснения типов своих данных в Haskell и Scala я использую REPL.
          Правильная IDE должна уметь это делать. Говорят кто-то умеет (для Scala), но я пользоваться IDE не умею, по этому не проверял.
      • 0
        Спасибо за Ваш ответ! Мне также хочется знать Ваше мнение о том, в каких проектах Вы бы не использовали Rust?
        • +1
          Прямо сейчас я бы не стал на Rust писать ничего серьёзного. Rust пока не готов к промышленному использованию.

          В будущем, подозреваю, на Rust не надо будет писать программы, которые нетребовательны к ресурсам, и которые возможно написать на Java. Проще программировать, когда есть сборщик мусора, и не надо знать обо всех этих тонкостях.
          • 0
            Очень Вы «нехороший» человек. Лишаете меня выходных. :)))
            Хочется задать еще один вопрос:
            При разработке на GoLang я использовал очень интересную фичу объекта testing, который передается в качестве аргумента в юнит-тесты. У этого testing есть возможность остановить замер времени и запустить замер вновь. Это использую из-за того что не хочу чтобы включалось время setUp, tearDown операций.

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

            Просто мне очень хочется иметь тесты вида «Алгоритм должен уложиться в… секунд». Бенчмарки позволяют видеть время, но они не оформлены в виде тестов и это немного мешает.
            • 0
              Может, оффтоп, но вам не кажется, что такие «тесты», не очень тесты? Все-таки, я могу запустить ваши тесты на кофеварке с линуксом и там они уже врятли пройдут, и это ничего не будет говорить про качество программы.
              Разумеется, это в предположении, что «алгоритмы» — это и впрямь алгоритмы из библиотеки алгоритмов общего назначения, а на обработчики сигналов, например.
              • 0
                >>но вам не кажется, что такие «тесты», не очень тесты?
                Тестирование производительности тоже тестирование. Не находите?

                >>я могу запустить ваши тесты на кофеварке с линуксом
                Да, согласен, но если я разрабатываю свое приложение исключительно на своей машине с определенным набором железа и при этом пользуюсь таким хорошим инструментом, то упавшие тесты, которые говорят «У тебя 5 алгоритмов стало работать дольше» и это мне очень помогает.
                Просто я юнит-тесты использую прежде всего для себя для проверки самого себя. Если есть возможность предоставить тесты в общую копилку, то да, это делаю, но если нет, то и не парюсь главное решить проблему по качественнее.

                >>что «алгоритмы» — это и впрямь алгоритмы
                Извините за капитанство, но: «алгоритм это последовательность действий выполняя, которую можно получить ожидаемый результат». Как правило, люди под «алгоритмом» воспринимают «общеизвестные алгоритмы», на вроде «сортировка Хоара» или «Поиск кратчайшего пути», но при этом опускают «общеизвестные». Однако разрабатывая какую-либо процедуру мы пишем ничто иное как последовательность действий приводящую к ожидаемому нами результату. Почему я не должен это называть алгоритмом? Процедура распаковки Malware модификации Trojan.Win32.Downloader.asdfasfd это тоже алгоритм и мне очень интересны ситуации когда подобные вещи вылезают за рамки после моих рефакторингов :) Сумбурно, но думаю Вы меня поняли
                • 0
                  Тестирование производительности тоже тестирование. Не находите?

                  Я не знаю, но, почему-то, везде это считается отдельной сущностью «бенчмарк».

                  Вообще, как я понимаю: тест они или «ок», или «неок». А бенчмарк (тест производительности), он не булевый, у него некий непрерывный спектр.
                  Я не евангелист TDD, так что я не уверен в кошерности моего подхода, просто для себя так определил.

                  Вообще, мне кажется, сложно сказать «хорошее» ли время выполняется код, или нет хотя бы потому, что всегда есть градации вроде «ну что-то не очень, но кажется, что сойдет» и еще сотня разных оттенков.
                  • 0
                    >>Вообще, мне кажется, сложно сказать «хорошее» ли время выполняется код
                    С точки зрения здравого смысла. А как иначе. Допустим Вы пишите функцию, которая по ссылке «yandex.ru» должна скачать содержимое. Что если она будет выполняться более чем 30 мин. Как Вы считаете это хорошая ситуация?

                    >>Вообще, как я понимаю: тест они или «ок», или «неок»
                    Да. Именно. Вполне даже юзабельно и полезно: «ОК, если функция про анализировала и выдала результат в пределах… секунд». Если вчера одна функция работала за одно время, а сегодня в тех же условиях, данных, машине после рефакторинга в 3 раза хуже, то это отличный сигнал о том, что Вам нужно повнимательнее присмотреться к своей работе.
                    • 0
                      Как Вы считаете это хорошая ситуация?

                      Зависит от сети, может, я с марсохода скачиваю на 100байт/c =)

                      Ваше время выполнения теста — специфично для вашего текущего окружения: процессор, память, сеть, диск, что угодно. С другим железом/ОС будет вообще другое время. Или слегка другое. Заранее не известно.
                      Вы что, при покупке новой машины пойдете все тесты переделывать в коде?

                      В моей работе такие тесты вообще бесполезны, я разрабатываю совсем не на тех машинах, на которых обо будет выполняться.
                      • 0
                        Я думаю нашу дискуссию лучше тут следует закрыть, мы стали отклонились от темы поста. Хотя готов пообщаться в личке, если есть желание.
          • 0
            В Rust обещают сделать указатели, аналогичные Rc, которые управляются сборщиком мусора.
            • 0
              Gc. Эти указатели будут task-local, а не глобальные, и сделают их ещё неизвестно, когда.
    • 0
      Не так давно на reddit было широкое обсуждение "Что вам не нравится в Rust", можете посмотреть.
      • 0
        Вот это мне кажется шагом назад по сравнению с C++:

        The amount of as_slice and to_string calls in my codebase is absurd.
        • 0
          C++ ушёл вперёд настолько далеко, что лучше бы он так далеко не уходил. Иногда лучше громоздкий код, чем слишком много магии в коде.

          to_string и as_slice, действительно, доставляют проблемы, но ссылаться на подход C++ как на истину и добро, точно не нужно.
        • 0
          Обилие to_string() с большой долей вероятности свидетельствует о неидиоматичной для Rust архитектуре.

          Обилие as_slice() — это известная проблема, но с недавнего времени вместо x.as_slice() можно писать x[]. А если as_slice() используется для вызова метода: x.as_slice().some_method(), то есть очень хорошие шансы, что в скором времени as_slice() не потребуется ни в каком виде: x.some_method().
  • 0
    Rust очень заинтересовал.
    Нашёл ещё пару видео про Rust на русском, сам пока не смотрел, про содержание ничего сказать не могу:
    video.yandex.ru/users/ya-events/view/2935/ — другое выступление Степана.
    vimeo.com/50492343
    Позже, может быть поищу на английском, там их конечно же намного больше.
  • +1
    Вы пишете «В данный момент язык программирования Rust ещё не начал использоваться в промышленном программировании». Это связано с какими-то техническими недоработками язык или с чем то другим? Меня интересует это с практической стороны — я хочу попробовать сделать веб сайт и меня интересует могу-ли я взять Rust или пока лучше все же языки вроде Java. Для Rust я так понял есть два популярных web frameworks Iron(http://ironframework.io/) и Nickel(http://nickel.rs/).
    • +1
      Просмотрел конец внимательней — нашел там ответ: синтаксис еще меняется, поэтому старый код может не откомпилироваться последней версией компилятора.
  • +1
    Ну назвать Java безопасной можно очень условно. Ошибки преобразования типов и обращений по указателю null в Java-программах встречаются регулярно.
    Rust и от них в большинстве случаев избавит.

    На Java и C++, все-таки, свет клином даже сейчас не сошелся. Достаточно часто можно написать шуструю и устойчивую программу на таких языках, как Haskell, *ML или Erlang. С++ их уверено рвет только в системах жесткого реального времени и при очень ограниченной памяти, как во встраиваемых системах.
  • 0
    Спасибо за полезный доклад. Добавлю пару слов.
    C-подобный язык, в котором придумали такое управление памятью называется Cyclone.
    Идея я Mutex<T> очень хорошая. Но ее и на C++ не сложно реализовать. А вот использование каналов делает программирование значительно более приятным.

    Кстати, проверка границы массивов делается только при обращении по индексу, а при использовании чего-нибудь типа map не делается, так как не нужна? Это было бы очень приятно.
    • +1
      Авторы Rust про Cyclone тоже знают:

      Additional specific influences can be seen from the following languages:… The memory region systems of the ML Kit and Cyclone.


      Идея я Mutex[T] очень хорошая. Но ее и на C++ не сложно реализовать.


      Как и каналы, и всё остальное, что есть в стандартной библиотеке Rust.

      Кстати, проверка границы массивов делается только при обращении по индексу, а при использовании чего-нибудь типа map не делается, так как не нужна? Это было бы очень приятно.


      При использовании map проверка границы, конечно же, делается. Чтобы понять, где заканчивать итерирование. При этом проверка делается ровно такое же количество раз, как и в C++, т. е. оверхед нулевой.
      • 0
        map может поместить размер коллекции в локальную переменную и проверять ее, что эффективнее за счет использования регистров и кеша.
        Кроме того, map по одному индексу читает одну коллекцию, а пишет в другую того же размера. Два раза проверять индекс ни к чему.
        • 0
          map() в Rust — это операция на итераторе, которая создаёт другой итератор. если вам нужна другая коллекция, то вам понадобится collect(). В итоге код может выглядеть так:

              let a = [1, 2, 3, 4];
              let v: Vec<int> = a.iter().map(|x| x*2).collect();
          


          collect() вообще не знает откуда он берёт данные, он просто скармливает итератор в реализацию трейта FromIterator, а эта реализация уже проходит по итератору и заполняет коллекцию. Поскольку итераторы умеют в size_hint, это получается довольно эффективно.

          Проверка границ происходит в реализации итератора, который возвращает iter(). Для срезов и векторов и там используется адресная арифметика, см. здесь.
  • –1
    Отложу до релиза других архитектур кроме x86(_64). Концепция языка интересная.
    • 0
      Насколько мне известно, раст успешно собирается кросскомпиляцией под арм и дальше отлично работает (собственно, движок Servo предназначен в первую очередь для мобильных платформ). Самому мне правда собрать не удалось, памяти не хватает.
      • 0
        Тогда попробую кросскомпилировать. Просто на сайте проекта только x86(_64) указаны.
        • +2
          Вот вам в помощь: github.com/rust-lang/rust/wiki/Doc-building-for-ios
          Для линуксового ARM в качестве target я указывал arm-unknown-linux-gnueabi.
          • 0
            Также надо иметь в комплекте уже готовый кросскомпилятор gcc под ту архитектуру.
            • 0
              Ну, в современных нормальных дистрибутивах это не проблема.
  • 0
    Вопрос к автору. А какая возможна ниша для Rust? Может он нацелен вытеснить C++ или вытеснить Java?
    • –1
      Rust — системный язык программирования, Java — нет, так что точно не вытеснить Java.
      • 0
        Область применения Rust может покрывать и область применения С/С++, и область применения Java. И, мне кажется, покрывает. Так что вытеснить java он может попытаться. Может быть, и не раст именно, но те языки, что будут использовать похожие идеи
  • 0
    Мне понравилась эта статься про Rust, может кому будет полезна: A 30 minute introduction to Rust
  • 0
    Спасибо за видео, очень познавательно. Жаль только, что о функциональных особенностях нет подробностей. Я недавно перешел с C++ на Scala, и назад теперь уже не очень хочется. Хотя, пока еще не знаю, как мой первый проект будет вести себя на VPS с ограниченным объемомо оперативки и без файла подкачки. Rust очень обнадеживает в этом смысле, но придется, во-первых, ждать релиза, и во-вторых, мне не совсем понятно, как он будет чувствоваться после всех функциональных «вкусностей» Scala.
  • 0
    А есть ли в rust аннотации по типу как java? чтобы написать что-то типа

    struct params{
    #[Argument]
    i8 x;
    }

    И оно положило в этот икс значение из командной строки, или из базы. Как в java делает например com.github.spullara.cli-parser или какой-нибудь ORM.
    При беглом поиске в документации ничего близкого не нашел.
    • +2
      В ядре языка точно нет. Rust позиционируется как достаточно низкоуровневый язык, пусть и с довольно удобными высокоуровневыми абстракциями там, где это возможно.

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

      Кроме одного варианта — плагины компилятора. Там ничто не мешает добавить новый синтаксис.
      • 0
        А насколько rust-2016 в отличии от 2014 готов для продакшена?
        В видео вы говорили, что раз в месяц у них менялся синтаксис чего-то и приходилось все поправлять. Насколько это изменилось сейчас? Появились ли с 2014 года какие-нибудь серьезные проекты на нем?
        • +1
          В видео вы говорили, что раз в месяц у них менялся синтаксис чего-то и приходилось все поправлять. Насколько это изменилось сейчас?

          После выхода версии 1.0 (15 мая 2015) все изменения обратно совместимы. Не считая исправлений ошибок, конечно, но обычный код такое не ломает.

        • +3
          Появились ли с 2014 года какие-нибудь серьезные проекты на нем?

          https://rustycrate.ru/adopters.html


          https://www.rust-lang.org/en-US/friends.html

        • +1
          Спасибо конечно, но на видео не я =) В целом на примере Servo — за последние пол года точно не было никаких существенных переделок из-за изменений в Rust, только улучшения. Язык достаточно стабилен. Пожалуй, можно использовать как основной. Иногда часть предупреждений становится ошибками в следующих версиях, об этом честно заранее предупреждает компилятор. Проблем не доставляет.

          В Firefox включают постепенно больше и больше кода на Rust. В данный момент парсер MP4 полностью на Rust. Планируется две крупных подсистемы — CSS и рендер. CSS (Stylo) уже влит в ветку Firefox, активно интегрируется.

          Помимо ссылок выше, могу добавить активное продвижение Rust в состав Gnome. Начали с библиотеки librsvg. В основном отзывы положительные.
          • 0
            Ясненько.
            А вы много на нем писали? Насколько вот эта концепция с передачей владения мешает, в сравнении с языками, где такой концепции нет (например java)?
            Я еще посмотрел разные примеры. У меня создалось впечтление, что у них там вместо точки с запятой в конце строки принято писать .unwrap(); Прямо вообще так часто пишут, что аж задалбывает. Вас не задалбывает это?
            • +3
              вместо точки с запятой в конце строки принято писать .unwrap();

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

            • +3
              По моим меркам не много — по времени около года, по количеству строк — около 10к.
              Концепция владения раньше мешала, теперь почти не замечаю. Тут два фактора: 1) привычка и осознание стиля языка 2) в новых версиях языка часть ограничений, связанных именно с несовершенством реализации, сняли, стало логичнее и проще. И да, на Java не писал вообще никогда. Писал на C++, C, Python из последнего/основного. На мой взгляд Java Rust не конкурент. А вот что теперь там, где раньше писал бы на C/C++ пишу на Rust, я очень доволен.
              unwrap() это утверждение, что если значение содержит ошибку — надо паниковать. В реальных проектах очень редко встречается. А вот к методам Result и Option — надо привыкнуть.

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

Самое читаемое Разработка