LINUX.ORG.RU

Rust 1.31.0 (2018)

 ,


5

10

Команда Rust объявила о выходе новой стабильной версии Rust 1.31.0, который ознаменует собой также выход новой редакции «Rust 2018». Rust — это язык программирования, который позволяет каждому создавать надежное и эффективное программное обеспечение.

Если у вас установлена предыдущая версия Rust, обновиться до Rust 1.31.0 проще всего следующим образом:

rustup update stable

Если у вас ещё не установлен Rust, то это можно сделать, загрузив с сайта утилиту rustup.

Что нового в Rust 1.31.0

Rust 2018

Данный релиз ознаменует собой выпуск редакции Rust 2018. Впервые Rust 2018 был упомянут в марте, затем в июле: прочтите их, чтобы понимать для чего нужен Rust 2018. Также, есть статья на сайте Mozilla Hacks.

Вкратце, Rust 2018 это возможность представить всю работу за последние три года в виде цельного пакета. Кроме возможностей языка, сюда входят:

  • Инструментарий (поддержка IDE, rustfmt, Clippy)
  • Документация
  • Работа различных рабочих групп
  • Новый веб-сайт

Для обозначения редакций Rust был представлен ключ edition в Cargo.toml:

[package]
name = "foo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"

[dependencies]

Значение 2018 означает, что используется редакция Rust 2018; отсутствие ключа или значение 2015 означает использование редакции Rust 2015.

Важно отметить, что каждый пакет может быть в редакциях 2015 или 2018, и они без проблем могут работать вместе. Проект под редакцией 2018 может использовать зависимости 2015, а проект 2015 использовать зависимости 2018. Это гарантирует целостность экосистемы, сохраняя совместимость существующего кода. Кроме того, существует возможность автоматической миграции кода с редакции Rust 2015 на Rust 2018 при помощи cargo fix.

Non-lexical lifetimes (NLL; Нелексические времена жизни)

В 2018 появились нелексические времена жизни, что на простом языке означает, что проверщик заимствований (borrow checker) стал умнее и теперь не отклоняет правильный код. Например:

fn main() {
    let mut x = 5;

    let y = &x;

    let z = &mut x;
}

В старых версиях этот код выдаст ошибку компиляции:

error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:18
  |
4 |     let y = &x;
  |              - immutable borrow occurs here
5 |     let z = &mut x;
  |                  ^ mutable borrow occurs here
6 | }
  | - immutable borrow ends here

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

Другой пример:

fn main() {
    let mut x = 5;
    let y = &x;
    let z = &mut x;
    
    println!("y: {}", y);
}

Старый Rust выдаст следующую ошибку:

error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:18
  |
4 |     let y = &x;
  |              - immutable borrow occurs here
5 |     let z = &mut x;
  |                  ^ mutable borrow occurs here
...
8 | }
  | - immutable borrow ends here

В Rust 2018 вывод ошибки стал лучше:

error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
 --> src/main.rs:5:13
  |
4 |     let y = &x;
  |             -- immutable borrow occurs here
5 |     let z = &mut x;
  |             ^^^^^^ mutable borrow occurs here
6 |     
7 |     println!("y: {}", y);
  |                       - borrow later used here

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

Пока эти возможности доступны в Rust 2018, но в будущем планируется портировать их на Rust 2015.

Изменения в системе модулей

Редакция Rust 2018 привносит некоторые изменения в работу с путями, что в конечном итоге привело к упрощению системы модулей.

Вкратце:

  • extern crate больше не требуется практически во всех случаях.
  • Макросы теперь можно импортировать при помощи use вместо атрибута #[macro_use].
  • Абсолютные пути начинаются с названия пакета, где ключевое слово crate ссылается на текущий пакет.
  • foo.rs и поддиректория foo/ могут сосуществовать вместе; mod.rs больше не нужен при размещении подмодулей в поддиректории.

Полную информацию можно прочесть в руководстве.

Упрощенные правила синтаксиса времени жизни

В обеих редакциях представлены новые правила синтаксиса времени жизни для блоков impl и определениях функций. Следующий код:

impl<'a> Reader for BufReader<'a> {
    // methods go here
}
теперь может быть написан таким образом:
impl Reader for BufReader<'_> {
    // methods go here
}

'_ подсказывает, что BufReader берёт параметр, но больше нет необходимости именовать его.

В структурах времена жизни всё ещё должны быть определены, но теперь без лишнего кода:

// Rust 2015
struct Ref<'a, T: 'a> {
    field: &'a T
}

// Rust 2018
struct Ref<'a, T> {
    field: &'a T
}
: 'a добавляется автоматически. При желании, можно продолжать использовать явное определение.

const fn

Существует несколько способов определения функций в Rust: регулярная функция с fn, небезопасная функция с unsafe fn, внешняя функция с extern fn. В этом релизе появился ещё один способ: const fn, который выглядит следующим образом:

const fn foo(x: i32) -> i32 {
    x + 1
}
Функции const fn могут вызываться как регулярные функции, но вычисляются во время компиляции, а не во время выполнения. Для стабильной работы, они должны иметь детерминированный результат и в настоящее время ограничены следующим минимальным набором операций:

  • Арифметические операторы и операторы сравнения с целыми числами
  • Все логические операторы, кроме && и ||
  • Построение массивов, структур, перечислений и кортежей
  • Вызов других функций const fn
  • Задание индекса массивам и срезам
  • Доступ к полям структур и кортежей
  • Чтение из констант
  • & и * на ссылках
  • Приведение типов, за исключением необработанных указателей на целые числа

В будущем данный набор будет расширяться, подробную информацию можно посмотреть здесь.

Новые инструменты

Наряду с Cargo, Rustdoc, и Rustup, которые являются ключевыми инструментами с версии 1.0, редакция 2018 представляет новое поколение инструментов: Clippy, Rustfmt, и поддержку IDE.

Clippy является статическим анализатором кода в Rust, достиг версии 1.0 и теперь доступен в стабильной версии Rust. Установку можно произвести следующим образом: rustup component add clippy, запуск: cargo clippy.

Rustfmt является инструментом для автоматического форматирования кода Rust в соответствии с официальной стилистикой Rust. В этом релизе он достиг версии 1.0 и, начиная с этой версии, гарантируется обратная совместимость для Rustfmt: отформатированный сегодня код останется неизменным в будущем (только с опциями использованными по-умолчанию), и несёт практическую ценность при использовании с системами непрерывной интеграции (CI; cargo fmt --check). Установить Rustfmt можно следующим образом: rustup component add rustfmt, использовать: cargo fmt.

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

Tool lints

В Rust 1.30 были стабилизированы атрибуты инструментов, такие как #[rustfmt::skip]. В Rust 1.31 стабилизированы «анализаторы инструментов» («tool lints») наподобие #[allow(clippy::bool_comparison)], у них появилось своё пространство имён и теперь ясно к какому инструменту они относятся. Старые проверки Clippy теперь можно писать следующим образом, вам больше не нужен атрибут cfg_attr:

// old
#![cfg_attr(clippy, bool_comparison)]

// new
#![allow(clippy::bool_comparison)]

Документация

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

Рабочие группы

В этом году было объявлено о создании четырёх рабочих групп в следующих областях:

  • Сетевые сервисы
  • Приложения командной строки
  • WebAssembly
  • Встраиваемые устройства

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

  • Группа сетевых сервисов работает над интерфейсом Futures и async/await, который уже будет доступен в скором времени.
  • Группа командной строки работает над библиотеками и документацией для создания ещё лучших приложений для командной строки.
  • Группа WebAssembly выпустила огромное количество инструментария для использования Rust с wasm.
  • Группа встраиваемых устройств добилась поддержки разработки ARM на стабильной версии Rust.

Новый сайт

Основной сайт получил новый дизайн.

Стабилизация библиотек

Добавлено множество реализаций From:

  • u8 теперь реализует From<NonZeroU8>, то же самое для других числовых типов и их NonZero-эквивалентов
  • Option<&T> реализует From<&Option<T>>, аналогично для &mut

Были стабилизированы следующие функции:

  • slice::align_to и её изменяемый аналог
  • slice::chunks_exact и её изменяемый и r аналоги (такие как slice::rchunks_exact_mut) во всех комбинациях

Подробный список изменений можно посмотреть здесь.

Cargo

Cargo теперь загружает пакеты параллельно, используя HTTP/2. В связи с тем, что extern crate практически больше не требуется, было бы неудобно использовать пакет через extern crate foo as bar; Это можно сделать в Cargo.toml следующим образом:

[dependencies]
baz = { version = "0.1", package = "foo" }

или

[dependencies.baz]
version = "0.1"
package = "foo"

В примере выше, пакет foo теперь может быть использован через baz.

Подробный список изменений можно посмотреть здесь.

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

★★★★★

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

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

Меня только интересовало, как создать sum type.

Ну так ни union, ни enum class для этого в C++ не подходят.

У rust нет сборщика мусора. Это определяющее для меня свойство языка.

Дело не в этом. Дело в том, что ряд основополагающих его возможностей создавались 40-30-20 лет назад.

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

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

На динамических языках точно так же пишутся юнит тесты

QA инженер заходит в бар, заказывает 1 пива, 1. пива, NaN пива, «» пива, {} пива, [] пива, [1] пива, [1.] пива, [NaN] пива, [«»] пива, [[]] пива, {"": 1} пива, {"": 1.} пива, ...

Приходит первый покупатель и заказывает 2 пива.

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

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

А я и не знаю, больше с чем сравнивать rust, кроме как с C++. Ну, ada еще есть. Только мне кажется, что ada ушла куда-то не туда. Да и опекун слишком серьезный.

Однако, есть один интересный момент. Rust нравится не только хардкорщикам (сишникам, плюсовикам), но и любителям ruby, к примеру, что меня несколько забавляет.

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

Дело не в этом. Дело в том, что ряд основополагающих его возможностей создавались 40-30-20 лет назад.

Те же enum rust позаимствовал из Algebraic Data Types ML образных языков (OCaml прямой родитель для rust), которые появились там тоже десятилетия назад, как бы и не раньше чем C++ родился.

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

Не с чем сравнивать, разве что с Delphi последнего разлива (кстати зомби немного оживает в последние годы) и с Ада в остальных везде gc.

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

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

Да можно и rust для этого взять, без этого понимания все-равно на нем нормально писать не получится.

Те, кто не могут разобраться с *(p+1), как показывает мой опыт, программисты так себе. У них мозги как-то по другому работают.

Такие точно на rust не смогут писать, так как для этого, кроме указателей, надо еще примерно такую же мозголомную вещь понимать - borrow checker. Еще хороший тест понимание рекурсии.

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

Rust нравится не только хардкорщикам (сишникам, плюсовикам),

Это несколько преувеличено.

но и любителям ruby

А вот это вполне возможно. В Rust тянутся из Python, из C# и пр.

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

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

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

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

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

Что в языке без RAII мешает управлять любым типом ресурса? Закрытие дескриптора в деструкторе — это только паттерн, один из возможных. К наличию GC не имеет отношения. Точнее, это одна из возможных вариаций scope-based resource management, есть и другие, всякие linear monad, resource monad и проч. Есть и более сложные паттерны управления контроля за ресурсом

http://kcsrk.info/ocaml/types/2016/06/30/behavioural-types/

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

У тебя какие-то странные кейзы. Не сталкивался с такими.

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

И это никак не связано с конкретным языком.

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

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

ну и таки-да, зачем const если есть mut если ты не видишь тупой избыточности, то ты слепец.

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

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

Сравнивать С++ный enum class с Rust-овым enum-ом... Ну это от большого ума, наверное. Типа, раз ключевые слова одинаковые, то и понятия они означают одинаковые.

Проблема в том, что в C++ попросту нечего сравнивать с такой простой вещью как enum в Rust. Разве что монструозный std::variant.

Да и вот та же перегрузка операторов в Rust-е: там как принято об ошибках информировать? Неужели паниками?

В Rust ошибка является частью типа функции. Оператор — это та же функция. Ваше кастомное сложение может возвращать Result если вам это нужно.

А это как бы ничего, что C++ 30 лет развивался эволюционным путем и Rust создавался, в том числе и с учетом всего этого опыта?

Это каким-то образом говорит в пользу C++?

Сравнивали бы Rust с его ровесниками (хотя бы относительными), типа Ceylon, Kotlin, Go.

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

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

Возможно, это будет просто языковой эксперимент.

Языковыми инструментами возможно стоит считать ATS, Agda, Idris, Clean, Coq, F*, Haskell 90х и начала нулевых, Rust это вполне себе инструмент который ничего нового не изобрёл, а только перенял удачные идеи из языковых экспериментов, которые до этого не мелькали в мейнстриме.

Был когда-то такой язык ioke. У его автора было несколько интересных идей. Например, что будет, если в языке методы отделять не точкой, а пробелом? А что если убрать из языка числа с плавающей точкой, а вместо них использовать рациональные дроби? И т.д. Чтобы проверить, будет ли так удобнее, он создал язык. Полтора года он его использовал. А потом подвёл итоги.

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

Вот, может, и в rust-е потестируют разные подходы, а потом лучшие из них добавят в C++/Java/etc.

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

Но так и быть, разжую немного — смерть C++/Java и прочих питонов с джаваскриптами предрешена. Неизвестно только как и когда, но судя по всему ждать осталось не так много, пузырь вот вот лопнет. Обратную совместимость поддерживать всё сложнее. Мейнстримные архитектуры процессоров дискредитированы, а с ними на пару дискредитирован C, как язык под который пилятся эти процессоры. Кроме это появляется всё больше ЯП с фичами, которые в «большие» языки не завести никак. Ну и как вишенка на торте — монополия Linux в сфере серверного ПО маячащая на горизонте.

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

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

Rust нравится не только хардкорщикам (сишникам, плюсовикам),

Это несколько преувеличено.

Как сказать. Упомянутую ранее книгу Programming Rust написали именно хардкорщики. Один - мейнтейнер GDB и других известных проектов, а второй работает (the module owner) над движком JavaScript в Firefox, где использует C++.

Что дает Rust хардорщикам? Дает уверенность в коде. Это не только мои слова, но и мое собственное ощущение тоже.

В Rust тянутся из Python, из C# и пр.

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

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

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

Ну вы сейчас просто опустили автора книг, разработчика jruby, seph, jopenssl, спикера множества конференций по языкам программирования. Что же тогда вы назвали бы языковым экспериментом?

Кроме это появляется всё больше ЯП с фичами, которые в «большие» языки не завести никак.

И какие же фичи нельзя завести в плюсы, шарп или яву?

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

Rust это вполне себе инструмент который ничего нового не изобрёл

Это было целью при разработке - ничего не изобретать. Но, AFAIK, им пришлось изобрести borrow checker.

смерть C++/Java и прочих питонов с джаваскриптами предрешена

Толстовато.

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

Как сказать.

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

* вы говорите «Rust нравится харкорщикам (сишникам, плюсовикам)». Поскольку в вашем высказывании нет ограничений, то может сложиться ощущение, что Rust нравится _всем_ хардкорщикам. Что не так. И приведенные вами единичные примеры являются лишь показателем того, что Rust нравится _некоторым_ хардкорщикам;

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

Т.е. суть моих претензий к вашим высказываниям вовсе не в том, что вы считаете Rust практичнее и удобнее. А в том, что вы как бы обвиняете C++ в том, что там (не)намеренно сделано непрактично и неудобно.

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

Проблема в том, что в C++ попросту нечего сравнивать с такой простой вещью как enum в Rust.

Из этой проблемы вовсе не следует, что enum class и union в C++ сделаны «не по уму». Поскольку они сделаны для решения совсем других задач.

В Rust ошибка является частью типа функции. Оператор — это та же функция. Ваше кастомное сложение может возвращать Result если вам это нужно.

Сразу видно теоретика.

Это каким-то образом говорит в пользу C++?

Простите, что вынужден расшифровывать примитивные вещи столь высоколобому теоретику, но фраза, на которую вы соизволили прореагировать, вовсе не про «пользу C++». Она про то, что сравнивая C++ и Rust высказывания вроде «здесь не по уму, а здесь по уму» некорректны.

Среди ровесников Rust известных в мейнстриме нет ни одного достойного языка программирования.
смерть C++/Java и прочих питонов с джаваскриптами предрешена.

Ой, проссыте. Вы не высоколобый. И даже не теоретик.

Вы из альтернативной реальности.

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

Юнит-тестами обычно покрывают локальную логику и обеспечивают покрытие кода.

И? Речь о том, что в статическом языке корректность этой логики гарантирует система типов, и тесты не нужны.

«программам на каждый чих»

Речь шла про valgrind, а не про тесты.

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

Но, AFAIK, им пришлось изобрести borrow checker.

Borrow checker — это такое newbie-friendly название linearity checker, который они всяко не изобрели. Просто первый мейнстрим язык с линейными типами.

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

Точнее, это одна из возможных вариаций scope-based resource management

Фишка в том, что для RAII с деструкторами scope-based resource management — это всего лишь один из сценариев.

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

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

Тестирование модулей — это кошмар? Серьёзно?

Вот и ответ на вопрос, почему многие здесь не любят «нестатические» языки. Потому, что они позволяют криворуким кодеришкам забивать на тестирование. И там, где программа на крестах честно упадёт и ЗАСТАВИТ искать ошибку, программа на каком-нибудь JS будет тупить, тормозить, делать не то, что нужно, наконец. И выявить, где кодеришка накосячил, будет сложнее, и на это во многих случаях просто забьют.

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

Rust, кстати, тоже язык преимущественно статический.

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

Я нормально отношусь к тому, когда сравнивают Rust и C++ применительно к решению какой-то задачи.

Ну вот, например, в Rust-е sum-types есть прямо в языке в виде удобных enum и match. В C++17 есть std::variant и std::visit, что a) явно не так удобно и b) это далеко не вся функциональность (тот же std::visit — это не match с контролем полноты и гардами).

Или, скажем, в C++ можно сделать шаблон, вроде std::array, который параметризуется скаляром, а в Rust нет (с воркароундом в виде использования макросов).

Вот такие сравнения нормальны.

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

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

Тестирование модулей — это кошмар?

Конечно, зачем писать тесты, если можно доказать корректность и сохранение инварианта на всей области определения?

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

Хуже, значит лучше? Написание тесткейсов руками с потенциальными ошибками, забытыми/некорректными кейсами лучше проверки типов?

где программа на крестах честно упадёт и ЗАСТАВИТ

Во время компиляции (при грамотной утилизации возможностей системы типов), это самое главное. Питоноподение упадет в рантайме.

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

Жопа есть жопа

Понял. Тут нет смысла что-то объяснять. Тут нужно на понятном публике уровне.

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

И да, жопа есть жопа, даже если она исторически сложилась и по-другому сделать было сложно. Хоть в C++, хоть в Rust-е.

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

Проблема в том, что в C++ попросту нечего сравнивать с такой простой вещью как enum в Rust. Разве что монструозный std::variant.

Кстати, а почему нет? Код на Rust:

enum WebEvent { KeyPress(char), Paste(String), }
[...]
match event {
    WebEvent::KeyPress(c) => println!("pressed '{}'.", c),
    WebEvent::Paste(s) => println!("pasted \"{}\".", s),
}

Выглядит похоже на код С++:

using Something = std::variant<double, std::string>;
[...]
std::visit(overloaded {
    [](double arg) { std::cout << std::fixed << arg << ' '; },
    [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, something);

По-моему, тут есть что сравнить.

PS: не могу развернуть в несколько строк - парсер лора выдаёт странное при попытке написать:

std::variant <
  double,
  std::string
[quote];[[/code]][/quote]

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

В Rust-е жопа с синтаксисом. В Rust-е жопа с ООП.

С этим в крестах не лучше, на самом деле.

В Rust-е жопа с обобщенным программированием.

В этом в расте сильно лучше, чем в крестах. В кресты даже концепты еще не завезли, параметры duck-typed.

что пришлось сверху прикручивать мощную систему макросов.

В этом крестам до раста вообще как пешком до луны.

В целом раст не ахти, конечно, но просто лет на тридцать впереди крестоубожества.

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

Мало того, в крестах компилятор еще и не может статически проверить exhaustiveness матчинга.

В каком смысле? Если выкинуть любую из двух лямбд - код не компилится.

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

Кстати, а почему нет?

Выглядит похоже на код С++

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

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

Ну зачем же так серьёзно. Я, в своё время, с большим интересом и энтузиазмом смотрел как продуманно в C(++) добавляют всё новые и новые концепты концепции. И не видел никаких оснований для критики. Сейчас тем более нет никакого смысла критиковать принятые решения задним числом - бесполезно и есть альтернатива.

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

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

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

Код-то не компилируются, только это не std::visitor заставляет проверять exhaustiveness, а самописные перверсии с шаблонами (которые тоже следовало написать, раз сравниваем раст с крестами) или static_assert, кому как нравится.

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

Код-то не компилируются, только это не std::visitor заставляет проверять exhaustiveness

Интересно, а кто же?

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

То в другом варианте.

Это же пример. В нём предлагаются разные варианты матчинга. Кто хочет — используют if constexpr и static_assert, кто хочет — используют вышеприведенный вариант без всяких ассертов.

PS: он std::visit, а не std::visitor.

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

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

Мелковато плаваешь, товарищ. У тебя какая-то нездоровая реакция на критику C++.

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

вышеприведенный вариант без всяких ассертов

То в другом варианте.

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

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

Borrow checker — это такое newbie-friendly название linearity checker

Borrow checker не имеет отношения к линейности (и в Rust нет линейных тмппов, кстати). Ссылки на предыдущие реализации borrow checker есть? Сссылки на определония того, что такое linearity checker?

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

Да и вот та же перегрузка операторов в Rust-е: там как принято об ошибках информировать? Неужели паниками?

Как уже упомянули выше, можно использовать Result в качестве результата операции:

use std::ops::Add;

#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Result<Point, ()>;

    fn add(self, other: Point) -> Self::Output {
        Ok(Point {
            x: self.x + other.x,
            y: self.y + other.y,
        })
    }
}

fn main() {
    let a = (Point { x: 1, y: 0 } + Point { x: 2, y: 3 }).unwrap();
    assert_eq!(a, Point { x: 3, y: 3 });
}
freecoder ()
Ответ на: комментарий от eao197

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

Так это же не баг, а фича ) Макросы в Rust - это очень здоровская штука, позволяет задавать абстракции на синтаксическом уровне. Удобнейшие возможности для всякого рода DSL, что гибкость (а занчит и потенциальную применимость) языка увеличивает на порядок.

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

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

В С++ скоро из-за того же самого прикрутят сверху метаклассы, а потом наверняка еще и добавят сверху и ast макросы. Лучше уж сразу прикрутить нормальные макросы чем отрезать хвост кусочками.

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

я про overloaded извращения с шаблонами

А он и без самописных overloaded обеспечит. Всегда, с любым callable object, иначе он просто не может развернуться в компилируемый код.

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

И? Речь о том, что в статическом языке корректность этой логики гарантирует система типов, и тесты не нужны.

Откуда дровишки? Как именно система типов гарантирует корректность логики, придуманной программистом, и что все бренчи выполняются как надо?

Речь шла про valgrind, а не про тесты.

Ответ был, что надо писать юнит-тесты, тогда не понадобится гонять валгринд на толстом коде.

Vit ★★★★★ ()