LINUX.ORG.RU

познать Rust

 


2

6

Доброго времени суток. Ищется материал по Rust, где:

1. В сжатой, но понятной форме изложено положение Rust в контексте других языков. В чём суть его новизны. В качестве базы ожидается C++, Java, Common Lisp. Желательно, с примерами кода.

2. Критика. Какие грабли уже проявили себя.

Желательный объём - до 5 страниц текста.

★★★★★

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

Ну вот совсем недавно проверял, результат работает также быстро, как код скомпилированный clang'ом.

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

Поля структуры (читай: базовые классы)

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

eao197 ★★★★★ ()

Желательный объём - до 5 страниц текста.

Ну вот, тебе лор нагенерил 5 страниц...

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

Какие возможности наследования нельзя поэмулировать агрегацией и автоматическим генерированием реализации интерфейсов базовых классов через делегирование? Мне в голову приходит только downcasting, который считается harmful.

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

С какой целью интересуетесь? Пытаетесь меня убедить, что изрядную часть геморроя, от которого вы освобождены в ООП языках, вы можете реализовать вручную на более примитивных конструкциях?

Да я же не спорю. Каждый трахается с разработкой софта в меру своей распущенности. Ну или прихотей тех, кто платит.

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

Нет, просто развожу на дискуссию о сравнении глубокого наследования (возможно с множественным проникновением) и агрегации.

Лично я думаю, что single inheritance вполне себе полезная штука, так как иногда бывает нужно именно is-a отношение между двумя классами.

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

Прошу прощения, но подобные дискуссии уже не интересны.

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

А поисковый запрос python 3 может найти библиотеки 3-ей версии для python 2.

Я всё-таки не думаю, что в расте будут настолько сильные ломающие изменения. В любом случае, искать библиотеки стоит через crates.io, а там, наверняка, будут указания совместимых версий, если до этого дойдёт.

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

Собственно, об этом и речь: нет наследования, поэтому Drop в Rust не есть полный эквивалент деструкторов в C++.

Ну тут мы во мнении не сойдёмся. Как по мне, «нет наследования» значит, что нет наследования и всё.

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

По твоему, в расте если не реализовать Drop, то для полей деструкторы не вызовутся? Там точно так же будет сгенерённый компилятором «деструктор». Соответственно, если реализовать деструктор для поля класса, то точно так же «ни для кого ничего не поменяется».

И ещё раз: это не «подмешивание внешних интерфейсов». В расте все методы - «внешние».

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

По твоему, в расте если не реализовать Drop, то для полей деструкторы не вызовутся?

Причем здесь поля? Как будто в C++ нужно определять деструкторы для того, чтобы вручную дергать деструкторы полей.

И ещё раз: это не «подмешивание внешних интерфейсов». В расте все методы - «внешние».

Ну OK.

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

Криво спроектированное говно - это в cpp. Вы хотите точно такое же, но не говно. В реальном мире если копировать говяное поведение - получится опять говно.

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

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

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

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

реализация того же DOM
мощных инструментов интеллектуального автодополнения
интеллектуальные инструменты разработки

Тебя продажники из MS покусали?

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

Причем здесь поля?

При том, что механизм такой же: если в процессе создания объекта вылетит исключение паника, то он не считается созданным, соответственно и деструктор/дроп для этого объекта вызываться не будет. А для уже инициализированных полей - будет. Это справедливо и для раста и для С++. Именно поэтому я считаю, что это один и тот же механизм.

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

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

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

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

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

И нет, finalize в java и Dispose в C# гораздо дальше от drop, чем cpp-шные деструкторы.

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

А вот подмешивание внешних интерфейсов/трейтов для того, чтобы явно что-то почистить в обновленной версии B, как раз таки и делает механизмы IDisposable и Drop сильно непохожими на деструкторы.

ты бредишь

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

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

На просьбу уточнить, что скрывалось за фразой «в rust есть» вы написали кучу однострочных сообщений в стиле «ты бредишь». И лишь одну вменяемую фразу «я говорил что в Rust есть деструкторы. Да, они не точно такие же, как в cpp», которая ничуть не противоречит исходному утверждению: «Выбрасывание исключений из деструкторов — это серьезная проблема, не имеющая простого решения. В других языках просто нет деструкторов, поэтому там проблемы другие.»

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

Я не понимаю, что вы мне пытаетесь доказать. В C++ есть механизм деструкторов. В Rust-е есть механизм Drop-ов, который Rust-оманы так же называют деструкторами.

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

А уже затем выяснять, в чем C++dstr и Rust-drop похожи, а в чем различаются.

Так, мы говорим про один аспект: что делать, если во время работы C++dstr/Rust-drop вылетает исключение/паника.

Попробуем с другой стороны посмотреть. Пусть у нас есть буфер/пулл, в котором мы хотим размещать объекты типа T. В C++ для создания объекта мы используем placement new, для разрушения объекта явно вызываем ~T. В Rust-е можем ли мы дернуть drop для структуры, которая не имплементирует для себя Drop?

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

den73 с другого компа

Спасибо, постараюсь вечерком посмотреть.

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

Ты о чём? Вот у нас на работе С++11 применяется. Со временем и на С++14 перейдём, пока что винда назад тянет. То есть это совсем не редкость.

У нас на работе

«У моей подруги с ее парнем...» (с) Делать глобальные выводы из себя немного неправильно :)

clang modernize, которые помогают обновлять код.

Для дотнета решарпер есть :) Только идиотам и бракоделам он не помогает :)

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

RAII в лиспе делаются на базе try..finally, если перевести на человеческий язык. Просто за счёт макросов получается меньше слов. Например, так сделан with-open-file. Я делал RAII для Delphi и для 1С, на интерфейсах (т.е. на RC). Не 100% надёжно (можно создать левую ссылку на объект, контролирующий ресурс, тогда деинициализация не сработает), но достаточно надёжно для моей практики, потому что я не создавал внешних ссылок.

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

Противоречит. Про бред я писал на совсем другой ваш ляп.

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

Противоречие было бы, если бы я утверждал, что «во всех других языках просто нет деструкторов».

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

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

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

У вас какая-то альтернативная версия русского языка, возвращайтесь когда перейдете на общепринятую.

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

Вы приписываете мне какое-то собственное восприятие мира. Прекратите, пожалуйста.

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

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

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

в Rust есть деструкторы. Да, они не точно такие же, как в cpp

И в чём же разница?

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

В Rust-е есть механизм Drop-ов, который Rust-оманы так же называют деструкторами.

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

Опять же, в Swift, насколько я могу судить, деструкторы имеются. Правда функция называется «deinit». Достаточно ли этого чтобы считать это другим механизмом? Как по мне - нет.

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

В Rust-е можем ли мы дернуть drop для структуры, которая не имплементирует для себя Drop?

Можем. Для примитивных типов, кстати, тоже можем (как и в С++).

Правда сам placement new в расте пока ещё «нестабильный»...

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

Делать глобальные выводы из себя немного неправильно :)

Дык, я же не делаю вывод, что «все используют С++11», а только, что такую работу найти реально. Опять же, друзья/знакомые и прошлые места работы тоже в «статистику» попадают. Как по мне, ситуация в среднем не такая и плохая.

Только идиотам и бракоделам он не помогает :)

Дык, им ничего не помогает. В том числе, и новые фичи языка, но это же не повод считать их бесполезными. (:

Ну и я понял твой изначальный аргумент как то, что «переписывать при каждом обновлении фреймворка не выгодно». Так вот хотел сказать, что именно переписывать, да ещё и всё сразу не обязательно. Даже от мелких изменений польза может быть. Ну а если код и так дописывается, то почему бы его понемногу и не обновлять заодно.

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

Другое дело, что аргумент в духе «не вижу разницы» или «считаю это разными вещами» сами по себе ценности не имеют.

Простите мне мой французский, но этот дурацкий разговор утомил сверх меры. В C++ деструкторы определяют много чего. Например, виртуальный ли деструктор или нет. В каком порядке вызываются деструкторы. Какие версии виртуальных функций доступны в конкретном деструкторе и т.д.

Ничего этого в Rust-овом Drop-е нет, потому что в Rust нет наследования.

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

То, что в контексте данного разговора функциональности Rust-овского Drop-а хватает для того, чтобы очистить какие-то ресурсы... Так я же с этим не спорю. В этом плане Rust-овский Drop предоставляет ту же функциональность, что и C++ный деструктор.

На счет «паники во время паники»... Думаю, что в C++ есть способ борьбы с классами, которые в деструкторах способны бросать исключения (как в случае с библиотекой OTL, например). Что-то вроде (всего лишь набросок):

class can_throw_in_dstr {
public :
   ~can_throw_in_dstr() {
      int rc = call_some_3rd_party_api();
      if(rc) throw system_error(rc);
   }
   ...
};
class cannot_throw_in_dstr {
public :
   cannot_throw_in_dstr() {
      m_dummy = new(m_dummy_buffer) can_throw_in_dstr(...);
   }
   ~cannot_throw_in_dstr() {
      try {
         m_dummy->~can_throw_in_dstr();
      } catch(...) {}
   }
   ...
private :
   char m_dummy_buffer[ sizeof(can_throw_in_dstr) ];
   can_throw_in_dstr * m_dummy;
   ...
};
При этом будет не суть важно, грохается ли cannot_throw_in_dstr в нормальных условиях или же из-за исключения.

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

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

Аналогично, но поспорить-то можно. (:

Если это вызывает негативные эмоции, то можем считать, что мы на этом и закончили.

Ничего этого в Rust-овом Drop-е нет, потому что в Rust нет наследования.

Так этого нет именно из-за отсутствия наследования, а не из-за неполноценности Drop. Ведь если написать на С++ программу, где не будет наследования вообще, но будут классы/структуры - это ведь не значит, что в ней не будет деструкторов.

Думаю, что в C++ есть способ борьбы с классами, которые в деструкторах способны бросать исключения

Перехватить панику в расте тоже можно, хотя это, в общем, случае и не приветствуется: считается, что паника - это всё-таки не исключения.

А вот вещей типа uncaught_exception, насколько я знаю, нет.

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

Так этого нет именно из-за отсутствия наследования, а не из-за неполноценности Drop.

Повторю еще раз: я не утверждаю, что Drop неполноценен. Просто из-за того, что в C++ с деструкторами связано несколько больше существенных для программы аспектов, то для меня Drop не является полным аналогом C++ного деструктора.

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

Перехватить панику в расте тоже можно

Так вроде бы это можно делать только на самом верхнем уровне рабочего потока. Или нет?

eao197 ★★★★★ ()

разработчики еще пока сами в процессе познания

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

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

Именно проблем? Например? Это уже не в контексте сравнения с растом, просто любопытно.

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

На всякий случай уточню - раст не предлагает ничего особенного и нового для Drop. Ну то есть он не решает больше проблем. Поэтому я в корне не согласен с maloi в плане того, что в расте сделано иначе/лучше. К сожалению, на вопрос он не ответил.

Так вроде бы это можно делать только на самом верхнем уровне рабочего потока. Или нет?

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

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

Именно проблем? Например?

Да навскидку взять хотя бы виртуальные функции. Даже опытные программисты забывают, что в деструкторе класса A будет вызвана версия виртуального метода f для класса A. Мол, A::f отвечает за очистку, вы у себя в наследнике ее переопределите, а мы сами ее дернем. Потом в В, унаследованном от A определяют f и чистят там какие-то специфические для B ресурсы. И выясняют при отладке, что в ~A вызывается A::f, а не B::f. Собственно, такая же картина и с виртуальными функциями в конструкторе.

Еще могут быть похожие грабли, когда в базовом типе A заводится атрибут-указать, значение которого начинает указывать на что-то в классе-наследнике. Обращаемся по этому указателю в ~A и получаем по рогам.

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

Да навскидку взять хотя бы виртуальные функции.

Ну ок, может быть. Хотя я это всё-таки проблемами не считаю. Скорее ошибками или неправильным использованием. То есть, проблема - ошибки (которые, вероятно, слишком легко допустить), а не возможности сами по себе.

С исключениями из деструкторов немного иначе - try/catch в них не всегда пишут, да и проблема из чужого кода появиться может. Плюс не зря же их, по умолчанию, noexcept сделали.

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

С исключениями из деструкторов немного иначе - try/catch в них не всегда пишут, да и проблема из чужого кода появиться может.

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

eao197 ★★★★★ ()

Спасибо за ссылки. Для себя делаю вывод:

в принципе есть интересные концепции, которые мне раньше не попадались. Такую концепцию я углядел одну: время жизни/одалживание указателя.

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

Рассуждения на тему графов, приведённые здесь,

https://aminb.gitbooks.io/rust-for-c/content/graphs/index.html

я не осилил. Я устроился на новую работу и мне, увы, стало не до разработки ЯП.

Очевидно, что там есть проблемы и что у поставщиков не было устраивающего хорошего решения. Также я думаю, а можно ли «красиво» реализовать Common Lisp на расте, где в граф организована, вообще говоря, вся память, и склоняюсь к выводу, что нельзя и что отсутствие сборки мусора будет критичной проблемой при попытке так сделать. Для меня дело пока выглядит так, что расту недостаёт общности и что задачу безопасного и защищённого от утечек управления памятью он не решает.

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

https://en.wikipedia.org/wiki/Region-based_memory_management

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

Касабельно озвученных проблем с дропами и деструкторами - наверняка всё это делается и в С++, и в Raste, просто может оказаться гораздо многословнее, чем ожидалось. Хотя в С++, учитывая ограничения области видимости объектов, может действительно оказаться проблемой. Впрочем, С++ мне не особо интересен, понятно, что в нём полно проблем и не все из них следует обсуждать, если цель состоит в том, чтобы «сделать хорошо».

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

Ещё интересна идея делать отдельную кучу для каждой «задачи» (т.е. треда)

Я не так понял или откуда ты взял, что это сделано в расте?

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

И почему же?

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

Я не так понял или откуда ты взял, что это сделано в расте?

прочитал пять заветных страниц текста

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

Ещё интересна идея делать отдельную кучу для каждой «задачи» (т.е. треда)

Я не так понял или откуда ты взял, что это сделано в расте?

Раньше так писали. Правда, мелким шрифтом поясняли, что разделение куч - концептуальное, а не физическое.

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

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

Думал, что может и правда когда-то так было... Всё-таки по расту хватает неактуальной информации.

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

Не совсем ясно, чем отличается концептуальное от физического? Если рассматривать с т.з. реализации сборки мусора (а не подсчёта ссылок), то даже концептуальное разделение памяти между тредами интересно.

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

то даже концептуальное разделение памяти между тредами интересно.

Дык, а в Erlang-е, например, это разве не так? Причем уже лет надцать как.

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

Не совсем ясно, чем отличается концептуальное от физического?

Тем, что память другого потока всё-таки можно расстрелять?

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

Просто это показывает уровень разработчиков Rust. Делать в 21 веке ЯП, для которого нет мощных инструментов рефакторинга, интеллектуального автодополнения...

и этот товарищ недавно кукарекал, как Rust затмит Go?

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

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

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

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

Разные кучи этому не помешают и не помогут.

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