Обновить
68
Владимир@Googolplex

Software engineer

25
Подписчики
Отправить сообщение

Вот здесь есть интересная статья про реализацию HashMap в Rust. Там, кстати, есть некоторое обоснование того, что открытая адресация (правильно сделанная) лучше цепочек.

Почитайте, пожалуйста, сайт, на который я скидывал ссылку. Все эти аргументы там разжёваны по много раз. Например, в 99% случаев для работы с текстом фиксированная длина code unit'а абсолютно не нужна.

Способен, конечно, но в Javascript (как и в Java, и во многих других языках, особенно на винде) используются UCS-2-строки. Из-за этого возникает много проблем, см. http://utf8everywhere.org/.

Помимо JavaEE есть ещё всякие вещи типа ATG, которые куда хуже :)

за исключением того, что на данный момент rustup-setup.exe паникует на Windows 8.1/10 и не устанавливает половину того, что должен.

Понятно. У меня просто нигде нет винды, поэтому я не знаю :) ну поэтому он пока что в бете. Думаю, что скоро всё это пофиксят.
Эх, не увидел :)
Хочу отметить, что недавно вышла бета rustup (репозиторий), утилиты для управления разными тулчейнами раста. Для винды там есть инсталлер. Это, на мой взгляд, самый удобный способ установки раста на любых системах.
Нет, не подразумевают

Что же это за такие интерфейсы?
отказывать себе в удобстве

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

Простите, но это настолько избитая тема, что я уже не хочу на неё отвечать подробно. Кратко — нет, это не то что требовалось доказать, и да, гарантия того, что подобные вещи возможны исключительно в unsafe, это game breaker. Единственный способ получить непроинициализированную переменную — это вызвать unsafe-функцию mem::uninitialized():
let x: i32 = unsafe { mem::uninitialized() };

И хотя бы поэтому случайно обратиться к неинициализированной памяти сложно. Особенно если у вас проекте указано #![forbid(unsafe)].
Так покажите это удобство.

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

В большинстве случаев early returns не используются. Кроме того, Rust — это expression-based язык, как Scala. Например, вместо тернарного оператора в нём if:
let y = if x > 0 { ... } else { ... };

Отсутствие необходимости писать return для возврата значения, если это значение — последнее выражение в функции, вытекает из этого совершенно естественно.
номинативную, через интерфейсы

Интерфейсы — это всё-таки немного не то. Если я не ошибаюсь, в D, как и в C++ и в Java, интерфейсы подразумевают динамическую диспетчеризацию. В Rust динамическая диспетчеризация используется только если вы сами её попросите (через трейт-объекты).
Вот полностью из песочницы на сайте

Такое сообщение появляется, если в качестве параметра add() используется нетипизированный литерал (42). Для удобства в Rust, как и во многих языках, числовые литералы могут автоматически принимать любой тип. Но в данном контексте он используется в качестве аргумента дженериковой функции, поэтому компилятор не может вывести тип литерала так просто. Вот такая ошибка возникает, если тип литерала указать явно (42i32):
<anon>:9:20: 9:23 error: the trait `core::ops::Add<&str>` is not implemented for the type `i32` [E0277]
<anon>:9     println!("{}", add(42i32, "eee"));
                            ^~~

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

Неинициализированные переменные ничем не инициализируются, если этого не указать явно, и нет, случайно обойти это ограничение нельзя в принципе. Одна из целей Rust — это гарантия полной безопасности работы с памятью; это включает в себя полный запрет на работу с неинициализированной памятью вне unsafe.
изменение типа в зависимости от того, какая функция была вызвана первой

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

Вам это так кажется. Редактировать и рефакторить такой код ничуть не сложнее, чем код без вывода типов, даже в чём-то проще — меньше печатать нужно. Почти не бывает такого, чтобы при рефакторинге тип переменной внезапно менялся, хотя бы потому, что объявлять отдельностоящие неинициализированные переменные неидиоматично. Кроме того, объявления типов обязательны в сигнатурах функций и констант/статических переменных, даже если они объявляются внутри другой функции.
Пример "действительной полезности" привести сложно — это всё-таки не фича уровня borrow checker'а, без которой невозможно жить, а элементарное удобство. Обойтись без этого можно всегда. Но я вот совершенно не могу придумать несинтетического примера, где это бы помешало. Специально сейчас пять минут посвятил просмотру кода своих библиотек, и не нашёл ни одного проблемного места.
А как всё же реализовать несколько точек выхода?

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

На самом деле здесь важны не сообщения об ошибках, а типобезопасность. В отличие от шаблонов в C++ или в D, дженерики в Rust позволяют применять к типам-параметрам только те операции, которые разрешаются ограничениями на эти параметры. В этом плане Rust ближе к языкам типа Java или к концептам (так и не вошедшим в стандарт, емнип) в C++. Ну и сообщение об ошибке на самом деле говорит какой конкретно типовый параметр неправильный, просто автор статьи не привёл это сообщение полностью. Вообще у rustc сообщения об ошибках просто феноменальные.
так как с ними много проблем

Ну в Rust с ними нет проблем, потому что переменные, которым ничего не присвоено, использовать нельзя, компилятор это проверяет статически и способа обойти это нет. То, как в Rust сравниваются объекты, зависит от реализации трейта PartialEq. В случаях, когда этот трейт автоматически выведен через derive (99%), то если структура состоит целиком из примитивных типов, то всё сведётся к побайтовому сравнению.
Очень опасный приём, особенно в свете множественной диспетчеризации

Вообще говоря, вывод типов — это безумно удобная вещь. Вы писали когда-нибудь на Haskell? В отличие от хаскеля, в Rust вывод типов исключительно локальный. Проблем с ним не возникает никогда, а удобства — выше крыши. И если под "множественной диспетчеризацией" вы понимаете перегрузку функций, то её в расте нет, так что этой проблемы не возникает :)
Да, безусловно, просто мне кажется что эмулировать всю поверхность ядра будет весьма проблематично/трудоёмко. Но действительно, гадать бессмысленно, посмотрим, во что это выльется :)
Если это действительно эмулятор-транслятор системных вызовов в win32 API, то, мне кажется, докер запустить в нём будет проблематично, потому что он сильно зависит на подсистемы ядра Linux (те же cgroups). Но запустить докер нативно под виндой было бы здорово, да.
Стоит отметить, что необходимое условие не является достаточным — из равенства ротора нулю потенциальность может не следовать. Собственно, в следующем предложении по вашей ссылке приведён пример непотенциального поля с нулевым ротором, а именно, если поле задано на многосвязной области, то даже если оно безвихревое, оно не является потенциальным. В английской вики про это написано гораздо лучше, чем в русской.

Собственно, если мы будем рассматривать область 2D-пространства, внутри которой есть магнит, то магнитное поле в ней не будет потенциальным, потому что любой криволинейный интеграл по замкнутому пути, охватывающем этот магнит, будет отличен от нуля. В трёхмерном пространстве же "простые" сплошные магниты не являются препятствием для выполнения достаточных условий потенциальности поля (например, нет такого замкнутого пути, интеграл по которому будет будет отличен от нуля), так что действительно, магнитное поле "простых" магнитов будет потенциальным.
Docker — кривоватый фронтенд к линуксовым контейнерам? о_О да уж. Даже если вам чем-то не нравятся детали его реализации, вы не можете отрицать, что подход докера к поставке и развёртыванию приложений сильно упрощает эти процессы. Я помню, как лет десять назад на локальном форуме в файлообменной сети провайдера я писал инструкции по настройке Apache+PHP+MySQL, и как это было довольно геморройно. Теперь с помощью докера их можно запустить одной командой в консоли — например, docker-compose up.
Kubernetes — это менеджер облачной инфраструктуры, etcd — распределённое строго консистентное key-value хранилище, Consul — service discovery. С другими перечисленными проектами я не сталкивался, но конкретно эти проекты (и докер, конечно же) весьма большие и используются в продакшне очень многими крупными компаниями. Ничего сравнимого на D, насколько я в курсе, нет. А ещё на Go написан gogs, с помощью которого (и с помощью докера) я поднял аналог гитхаба для личных нужд за десять минут.
Не поймите неправильно, я лично Go не очень люблю, я фанат Rust, и лет пять назад я немного писал на D и даже слал им баги в багтрекер. D мне весьма понравился, особенно по сравнению с C++, на котором я тогда тоже чуть-чуть писал. Но тогда у D, например, не было нормального пакетного менеджера, не было нормальных библиотек почти ни для чего, и были очень противные баги в компиляторе, которые долго не чинились. Поэтому лично меня не зацепило сильно. Если бы сейчас не было Rust'а, есть вероятность, что я бы писал какие-то свои проекты на D.
Для нормального функционального программирования необходимы (но не достаточны!) либо полноценный параметрический полиморфизм (т.е. дженерики; например, это языки ML-семейства), либо полная динамичность (лиспы, эрланг). Go не имеет ни того, ни другого, и поэтому максимум, что про него можно сказать, это то, что в нём есть функциональные элементы.
Но это, безусловно, не значит, что язык плохой — просто он задумывался для другого, и его основные практики и подходы тоже другие.
Аннотации — это немного из другой оперы. Аннотации — это просто статические метаданные, которые можно проанализировать через отражение. А декораторы — это активные преобразователи функций. Декоратор оборачивает одну функцию в другую. Вероятно, в каком-то виде они могут добавлять метаданные по типу аннотаций, но это зависит от языка, я думаю. С точки зрения Java декораторы ближе к AOP-фреймворкам, чем к аннотациям. Просто так получилось, что синтаксис у них похожий.
Хочу отметить, что "derive" — это не "извлечь", это "вывести". Ну грубо говоря, как на бумаге мы можем вывести одну теорему из другой, смысл именно в этом. Этот термин в данном контексте вообще пошёл из Haskell, где при определении новых типов можно указать deriving (...) и в скобках перечислить тайпклассы, которые нужно автоматически вывести для нового типа на основании его содержимого. Поскольку трейты — это на самом деле тайпклассы, взять эту функциональность из Haskell было весьма логичным и напрашивающимся решением.
Проверяли, и это просто один из множества подобных мифов :)
Вы меня, конечно, извините, но это чушь. В частности, int – самый приемлемый тип целочисленных данных для текущей платформы. Если речь идет о быстрых беззнаковых целых, как минимум, на 16 битов, нет ничего плохого в использовании int (или можно ссылаться на опцию int_least16_t, которая прекрасно справится с функциями того же типа, но ИМХО это куда подробнее, чем оно того стоит).


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

Например, есть такой очень классный плеер, deadbeef. Он написан на С и вполне себе кроссплатформенный. Однако зачем-то его авторы решили придумать свой формат плейлистов, причём не текстовый, а бинарный. И в этом формате используются платформозависимые типы данных, с платформозависимым порядком байт. Писать программу не на C (конкретно — на Rust) для разбора плейлистов из-за этого было больно. Кроме того, я более чем уверен, что если deadbeef запустить, скажем на ARM, и скормить ему плейлист, сделанный им же, но на Linux x86_64, то он его не проглотит вообще.

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

В общем, если программа на C пишется исключительно для себя и на один раз/для одного конкретного применения, то, вероятно, платформозависимые типы использовать можно. Но если программа должна быть хоть сколько-то кроссплатформенной, то использование платформозависимых типов эквивалентно созданию минного поля из граблей с привязанными топорами. А уж если это библиотека, которая предполагает использование из других программ, то неиспользование фиксированных типов это просто неуважение к её пользователям.
Сейчас, с современными init-системами, делать самофоркающиеся демоны — это моветон. Гораздо проще написать программу, которая работает как обычно и пишет логи в stdout. После этого написать юнит для systemd или что-то аналогичное — и все «фичи» демона становятся доступны автоматически.

Информация

В рейтинге
Не участвует
Откуда
Santa Clara, California, США
Дата рождения
Зарегистрирован
Активность