LINUX.ORG.RU

Вышел Rust 1.23

 ,


2

9

4 января состоялся плановый релиз компилятора и стандартных средств разработки системного языка программирования Rust — 1.23.

Интересные изменения:

  • За счёт предотвращения ненужного копирования аргументов функций уменьшено потребление памяти. Например сам компилятор rustc стал потреблять на 5-10% меньше памяти.
  • rustdoc перешёл на рендеринг документации при помощи CommonMark. Раньше использовался Hoedown.
  • The Cargo Book переехал с doc.crates.io на doc.rust-lang.org и обновил формат.
  • cargo uninstall научился сразу удалять несколько пакетов. Например, команда cargo uninstall foo bar удалит foo и bar.
  • auto трейты теперь разрешены в трейтовых объектах. Один из коммитов этого изменения также окончательно удалил элемент языка send.
  • Проверки типов операндов бинарных операторов теперь производится относительно левого операнда, что предотвращает путаницу в соответствующих сообщениях об ошибках.
  • Исключена необходимость в T: Sync для RwLock<T>: Send.
  • Исключена необходимость в T: Sized для {<*const T>, <*mut T>}::as_ref и для <*mut T>::as_mut.
  • Оптимизирована реализация Thread::{park, unpark}.
  • Улучшена производительность SliceExt::binary_search.
  • Трейт AsciiExt объявлен устаревшим, а его методы перенесены в примитивные типы.
  • char::escape_debug теперь использует Unicode 10 вместо Unicode 9.
  • Включён LLVM-флаг TrapUnreachable.
  • musl, используемый для сборки musl rustc, обновлён до 1.1.17.
  • Улучшена производительность SliceExt::binary_search.
  • rustfmt включён в основную инсталляцию.
  • Минимальная версия LLVM изменена на 3.9.

Полный перечень изменений

>>> Анонс

★★★★★

Проверено: Shaman007 ()
Последнее исправление: tailgunner (всего исправлений: 5)
Ответ на: комментарий от shkolnick-kun
    bgrt_bool_t roll=(bgrt_bool_t)1;

    while ((bgrt_bool_t)roll)
    {

Да, действительно переносимый код, с этим не поспоришь.

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

Если я в «конструкторе» делаю malloc, а Drop не делаю free - то я получаю утечку.

А учитывая, что у Rust'а ручное управление памятью - то это вполне нормально поведение.

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

Мы говорим не про unsafe

А без unsafe вы не можете работать с сырой памятью.

там это по другому делается

Внутри обычный jemalloc, если что.

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

Внутри обычный jemalloc, если что.

Мы это г3ецо выключаем в федоре.

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

А зачем мне самому работать с сырой памятью? Кроме того Drop для этого точно не предназначен.

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

а как по-твоему сделать биндинги к сишным библиотекам? кто будет делать unref(), free(), ...?

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

Стало интересно, посмотрел что говорит по этому поводу википедия:

In common usage, a destructor is a method called deterministically on object destruction, and the archetype is C++ destructors; while a finalizer is called non-deterministically by the garbage collector, and the archetype is Java finalize methods.

Так что все таки ты не прав, Drop это деструктор а не финализатор.

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

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

Вот от туда же о том, что такое финализатор:

In object-oriented programming, a finalizer or finalize method is a special method that performs finalization, generally some form of cleanup. A finalizer is executed during object destruction, prior to the object being deallocated, and is complementary to an initializer, which is executed during object creation, following allocation.


А вот как Википедия определяет деструктор:

In object-oriented programming, a destructor (dtor) is a method which is automatically invoked when the object is destroyed. It can happen when its lifetime is bound to scope and the execution leaves the scope, when it is embedded in another object whose lifetime ends, or when it was allocated dynamically and is released explicitly. Its main purpose is to free the resources (memory allocations, open files or sockets, database connections, resource locks, etc.) which were acquired by the object during its life and/or deregister from other entities which may keep references to it.


Чувствуешь разницу? Я выделил для тебя важную часть.

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

Умели бы Java интерфейсы в self-типы, то разницы совсем бы не было

Что значит это твоё «уметь в self-типы»? Интерфейс просто определяет набор методов и их сигнатур, которые должны быть реализованы. Реализацию метода по умолчанию, добавленную в Java 9, можно пока не рассматривать.

bbk123 ★★★★★
() автор топика

А мне нравится Basic. В крайнем случае - Pascal...

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

Its main purpose is to free the resources (memory allocations, open files or sockets, database connections, resource locks, etc.) which were acquired by the object during its life and/or deregister from other entities which may keep references to it.

Правильно, именно для этих целей и предназначен drop. Тот же самый File, например, нельзя закрыть не вызвав деструктор, у него даже метода close() нету. Могу привести тебе примеры для всех пунктов из этого списка в стандартной библиотеке раста:

memory allocations

open files or sockets

database connections

Баз данных нет в стандартной библиотеке раста, но можно найти в сторонних библиотеках, например sqlite Connection

resource locks

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

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

А это неправда, в расте управление памятью такое же как в C++, ничего нового не добавили, просто убрали new и delete, а все остальное осталось точно такое же. Например Box это аналог std::unique_ptr, а Arc это std::shared_ptr.

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

Правильно, именно для этих целей и предназначен drop. Тот же самый File, например, нельзя закрыть не вызвав деструктор, у него даже метода close() нету.

Ты путаешь файл и то, где он использеуется. Ты можешь закрыть файл просто выйдя из скопа, в котором ты его объявил. Тебе совсем не обязательно закрывать его в своём drop или вообще ждать пока твой drop будет вызван. Если твой файл является полем твоего struct, он так же будет закрыт автоматически во время удаления твоего struct или если ты его передашь в другой скоп (например в функцию) и просто вернёшься от туда. Для этого тебе опять же свой drop не нужен. Свой drop тебе может понадобиться если ты захочешь дописать в файл нечто перед его закрытием. Это и есть финализация. Это не деструктор, хотя деструкторы в C++ могут делать и финализацию. Обязанности деструкторов шире, чем обязанности финализаторов.

memory allocations

  • RawVec
  • RawTable
  • Arc и Rc

А memory deallocations? Приведи аналог delete, который не вызывается автоматически и который необходимо вызывать самому, иначе память начнёт течь?

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

А это неправда, в расте управление памятью такое же как в C++, ничего нового не добавили, просто убрали new и delete, а все остальное осталось точно такое же. Например Box это аналог std::unique_ptr, а Arc это std::shared_ptr.

Не точно такое. Простое наличие умных поинтеров не делает их использование обязательным. Как и наличие std::move. Можно сказать, что в Rust автоматическое управление памятью реализовано при помощи тоталитаризма - программиста заставляют писать код определённыи образом. Именно поэтому drop превратился в финализатор, как и в других языках программирования с автоматическим управлением памяти.

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

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

Это ложь.

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

Это ложь.

Это голословное заявление

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

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

Это уже игра формулировками. Можно сказать, что, в отличие от C++, программиста заставляют использовать умные поинтеры. А потом, после возражения, добавить «оставаясь в рамках safe-rust». Или можно сказать, что rust - это тот же самый C++ в котором есть и умные и ручные указатели, но ручные указатели и new/delete запихали в гетто.

По-моему это никак не связано со спором о деструкторах. Идея конструкторов/деструкторов обладает одним большим недостатком: конструкторы по определению безымянные и различаются через типы параметров, что заставляет либо изгаляться с типами параметров new StopWatch(Seconds(10)), new StopWatch(Milliseconds(10000)), либо передавать дополнительным параметром уточнение, либо как-то различать в рантайме (передавать в строке и парсить, например), либо либо добавлять вариант создания через статический метод только чтоб его именем уточнить вариант конструктора StopWatch::FromSeconds(10). Авторы Rust решили заменить все конструкторы именованными статическими методами, чтоб не было порнографии, когда простое создание объекта пишется либо new StopWatch(10000), либо new StopWatch(StopWatch::FromSeconds(10)). Соответственно, после того как от конструкторов избавились, стало как-то не в тему иметь деструкторы, вот их тоже разжаловали в обычные методы. Аналогия с Finalize тут не в тему.

khrundel ★★★★
()

Мне всё-таки интересно, чем язык лучше, чем golang? Вроде и тот и другой заменяют плюсы. Ещё, я заметил, что как и scala имеет _ переменную, любое выращивание имеет значение... Все ли синтаксические «извращения» scala он поддерживает?

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

Мне всё-таки интересно, чем язык лучше, чем golang?

Тем, что есть нормальные AlgDT и дженерики.

Вроде и тот и другой заменяют плюсы.

ШТА? Go - замена Python для индусов с задержками в развитии.

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

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

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

По-моему это никак не связано со спором о деструкторах.

Связано, поскольку отражается на том, что нужно делать в том, что сишники по привычке называют деструкторами в Rust. Вся деструктивная функциональность от туда исчезла, осталась лишь финализирующая. Именно поэтому fn drop() правильно называть финализатором, а не деструктором.

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

Не только, ещё переводы сравнений языков на хабре

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

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

Ну а я потом сформулировал иначе, оставив всё как в С++, только обозвав часть возможностей «неполноценным» растом. При такой формулировке нет разницы между управлением памятью в современном C++ со всякими unique_ptr/shared_ptr (где, кстати, за излишние new/delete можно получить по башке от тимлида) и Растом (где тимлид будет бить по башке за ансейф).

Связано, поскольку отражается на том, что нужно делать в том, что сишники по привычке называют деструкторами в Rust. Вся деструктивная функциональность от туда исчезла, осталась лишь финализирующая. Именно поэтому fn drop() правильно называть финализатором, а не деструктором.

Вообще-то это практически синонимы, просто берётся один из вариантов авторами языка. Всё это код, который выполняется перед освобождением памяти. Но в тех случаях, когда всё-таки различают, определяющим моментом является именно детерминированность, если GC - тогда финалайзер, вызывается когда-нибудь, если ручное управление или смартпоинтеры - деструктор. Есть исключения, например в C# финализатор иногда называют деструктором чтоб меньше отличаться от C++.

А вот различение по «деструктивной» и «финализирующей» функциональности - это как раз бред сивой кобылы. Финализаторы в языках с GC вполне себе могут вызывать деаллокацию неуправляемой памяти, могут вручную вызывать освобождающий код для полей с объектами из кучи (например Dispose в шарпе). Деструкторы из крестов, с другой стороны, не вызывают явно уничтожение полей объекта, о том, чтоб вызвать деструкторы полей заботится компилятор. Так что, при всей тонкости различия деструкторов и финализаторов, drop - это всё-таки деструктор, так как 1) вызывается детерминированно. 2) обходится без вызова «финализации» для внутренних полей объекта.

С finalize из java у drop общего только то, что синтаксически оформляется как обычный метод.

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

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

Но finalizer в Java никогда не инициирует освобождение памяти и даже не обнуляет поля класса финализируемого объекта, чтобы как-то помочь GC, который в такой «помощи» просто не нуждается.

если GC - тогда финалайзер, вызывается когда-нибудь

Одной из первых реализаций GC было reference counter. В этом случае не когда нибудь, а строго детерменировано.

А вот различение по «деструктивной» и «финализирующей» функциональности - это как раз бред сивой кобылы.

Прочти последний абзац перед началом главы 9.2
https://books.google.com/books?id=8v9vZMPV3scC&pg=PA120

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

Но finalizer в Java никогда не инициирует освобождение памяти и даже не обнуляет поля класса финализируемого объекта, чтобы как-то помочь GC, который в такой «помощи» просто не нуждается.

Вполне может делать всё это. Может освобождать память, если объект содержит ссылку на неуправляемую память. Например на буфер, выделенный нативной функцией. Даже так: «может» тут излишне: финализаторы именно для этого и созданы.

Более того, статистически финализатор намного чаще обнуляет поля класса чем деструктор, потому что деструктор гарантировано вызывается только перед смертью, нет никакого смысла занулять указатели в области памяти, которая сейчас освободится, а финализация объекта часто реализуется в двух экземплярах, через close/Dispose и через finalizer, поэтому код, фактически выполняющий финализацию, часто зануляет поля, чтоб вести себя адекватно при возможном повторном вызове.

Раз уж мы рассматриваем конкретно C++ и Java, есть ещё одно различие. Финализатор в Java может «спасти» объект, добавив ссылку на него куда-нибудь. Например он может обнаружить в объекте несохранённые изменения, вызвать асинхронно операцию сохранения, чтоб поток финализации не ждал завершения дисковой операции. В итоге объект сможет после завершения финализатора ещё часами сидеть в памяти и переживёт несчётное количество сборок мусора. drop так сможет? Нет.

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

khrundel ★★★★
()

Rust и C++ избытачны ООП избыточно — вот истина

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

Для системного программирования достаточно няшной Растишечки.

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

Btw, финализаторы ужастны. Вместо них если очень нужно надо использовать PhantomReference

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

drop так сможет?

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

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

Сильно сомневаюсь, по выходу из дропа объект уничтожится, асинхронная функция должна либо забрать объект во владение (что из дропа невозможно, объект занят self ом), либо объект должен иметь статический лайфтайм (что в виду дропа тоже не вариант), либо будет какой-нибудь guard с ожиданием в деструкторе, что фактически превратит код в синхронный.

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

drop принимает аргументом &mut self, так что если сохранить ссылку на этот обьект, то это будет нарушением aliasing rules.

pftBest ★★★★
()

А где, кстати, царь? Почему не проводит разъяснительную работу среди педе-rust-ов? =))

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

1) Вам там уже указывали, про intX_t. Типы НЕ обязательные, но есть приписка:

7.18.1.1 Exact-width integer types в C99 7.20.1.1 Exact-width integer types в C11

These types are optional. However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall define the corresponding typedef names.

2) есть поддержка utf-8 через префикс строк u8, есть поддержка Unicode через префиксы u/U. Строкового типа нет - Вы-же не ожидаете его наличия в ассемблере? А всё остальное да - решается библиотеками.

встречный вопрос - будет-ли Rust программы собираться и работать на аппаратных платформах, у которых нет типов [ui]8/[ui]16 - по типу разный Cray-ев. И, кстати, товарищи, которые разрабатывают Rust, тоже не сразу такие умные стали - одно время у них были типы int/uint полностью аналогичные C-шным, как я понимаю. И ещё вопрос - как у Rust с поддержкой типа long double который 80 бит? Понятно, что x87-сопроцессор это старьё, но как-бы он есть.

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

будет-ли Rust программы собираться и работать на аппаратных платформах

Компилятор Rust есть только в одном варианте - на основе llvm, соот-но список платформ равен тому, что умеет llvm.

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

тут больше не вопрос к llvm, тут больше вопрос к требованию обязательного наличия типов [ui]8/[ui]16. Получается, что т.к. у Cray-я таких типов нет, то и Rust там работать не будет, даже если таковую поддержку в llvm завезут. Просто для C будет истинно sizeof(char) == sizeof(short) == sizeof(int), типов int*_t не будет, а будут int_least*_t и int_fast*_t. А для Rust-а, где, как я понимаю, требуется обязательное наличие 8-ми и 16-тибитных целочисленных типов, просто невозможно выполнить это требование.

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

Ну и когда же Вы в последний раз писали ПО для Cray?

upd: Не серьёзно, все более менее живые платформы имеют одинаковую разрядность, если нет, ну приведите нам пример современной машины где байт != 8 бит или где 32\64 бита не будут составлять машинное слово?

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