LINUX.ORG.RU

Имеет ли смысл использовать Rust для написания библиотеки?

 ,


2

3

Есть желание написать одну библиотеку. Она может использоваться в разных языках и на разных платформах. В частности важно, чтобы не было проблем на Windows. Работать должна быстро, памяти потреблять мало. Логичный выбор - С. Использовать можно из любого языка, накладных расходов почти ноль.

Но про Rust много базза в последнее время и, т.к. проект just for fun, стало интересно, имеет ли смысл такое делать на нём? Готовы ли инструментальные средства для генерации DLL на всех платформах? Не будет ли проблем с интеропом (C++, Python, Objective C)? Какой результирующий объём бинарников, необходимых для распространения? Скажем, С-шная DLL-ка будет весить совсем немного, а стандартная библиотека есть практически на всех платформах.

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

★★★★★

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

В смысле любой вариант, который позволит использовать существующий C и C++ код, без существенных переделок и написания прослоек. Синтаксическая совместимость слишком сильное требование, оно тому же C++ сильно кровь попоротило, очень многие проблемы от сишечки в крестах. Можно на уровне ..хм.. «модулей», т.е. пары хидер + .c/.cpp/.a/.so. Ну или что-нибудь в этом духе... Но тут нужно иметь в виду, что язык должен уметь готовить крестовые шаблоны и пр. прелести.

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

А про пример на шаблоны/дженерики есть что ответить?

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

Мне больше нравится подход Ржавчины, с разделением обобщенного кода на три вида, отличающихся по мощности и, соответственно, простоте:

  • встроенные в язык простые дженерики с трейтами - они просты как деревяшка и их хватает в большинстве случаев;
  • обычные макросы (которые macro_rules!) - их хватает для большинства оставшихся случаев;
  • ну и процедурные макросы (их, вроде, синтаксическими расширениями или плагинами еще обзывают), работающие с полноценным синтаксическим деревом - самое мощное из имеющихся средств кодогенерации, но и работать с ними сложнее.

Как мне сделать для некоторого dict<T> метод доступа к элементу(operator[] в случае C++) так, чтобы он сам создавал элемент, если такового нет, но при этом dict<T> мог бы успешно работать с типами, которые не имеют конструктор по умолчанию, просто данные метод для них бы не работал и выдавал ошибку времени компиляции при попытке его вызвать?

По поводу самого примера - один в один, конечно, не получится, подходы к метапрограммированию разные. Точно так же в С++, пока не введут концепты, нельзя выдать ошибку сборки об использовании некорректного типа (у которого нет нужного метода), пока не вызовешь метод, для которого нельзя сгенерировать код из шаблона. Мне это напоминает ситуацию с динамически и статически типизируемыми языками, и на последних мне писать/изменять большие программы нравится намного больше.

Самый близкий к плюсовому коду вариант, который у меня вышел: http://is.gd/DIAUCe (там есть кнопка evaluate, можно поиграться).

Код, конечно, имеет мало общего с идиоматической Ржавчиной. Не думаю, что кто-то на практике бы стал использовать подобное.

У макросов нет отложенного инстанцирования, так что просто вызов метода тут не поможет - надо макрос get! явно вызывать. И я не знаю как выдрать тип переменной, которую надо сохранить в словаре, так что тип передается явным образом при вызове макроса, некрасиво :( .

... не надо про trait'ы - это не совсем то ...

Хмм, вроде уже где-то обсуждалось, но не могу найти. Можно еще раз озвучить фатальные отличия? А то, вроде, довольно близкие штуки.

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

По поводу самого примера - один в один, конечно, не получится, подходы к метапрограммированию разные

Это не метапрограммирование. Это обобщенное программирование.

вариант, который у меня вышел: http://is.gd/DIAUCe

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

Хмм, вроде уже где-то обсуждалось, но не могу найти. Можно еще раз озвучить фатальные отличия? А то, вроде, довольно близкие штуки.

Если не сильно вдаваться в подробности, то концепты описывают типы, а trait'ы - интерфейсы объектов. Скажем, для концепта совершенно нормально потребовать тип container::iterator.

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

Дело не в этом. Просто возможностей меньше(см.выше). Неужели так сложно спроектировать язык, не уступающий ни в чем крестам?

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

Я не думал что слово «переписывает» воспримут так буквально. :)
Библиотека реализующая гугловский протобафер протокол.

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

Дело не в этом. Просто возможностей меньше(см.выше)

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

Неужели так сложно спроектировать язык, не уступающий ни в чем крестам?

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

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

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

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

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

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

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

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

У тебя очень своебразное понимание «ни в чем не уступает крестам».

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

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

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

Я не сравнивал скалу и кресты с точки зрения замены, ибо скала - это другая ниша. Это просто пример языка с широкими возможностями и без существенной боли. Хотя многие и её ругают схожим с типичной ругонью крестов манером... Но, видимо, «there are only two kinds of languages: the ones people complain about and the ones nobody uses» (c) Bjarne Stroustrup.

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

Это не метапрограммирование. Это обобщенное программирование.

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

В смысле? Плюсовые шаблоны - это не метапрограммирование (хммм... http://en.wikipedia.org/wiki/Template_metaprogramming)? Всегда считал, что обобщенное программирование - это частный случай метапрограммирования. Да и SO, вроде, со мной согласен: http://stackoverflow.com/a/3937852.

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

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

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

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

Лютая вкусовщина же. Провести бы нормальный массовый опрос людей, которые одинаково знают плюсы и ржавчину (или хотя бы поверхностно знают оба языка), тогда подобные утверждения были бы интересней.

... макросы на ровном месте...

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

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

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

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

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

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

Если бы инструменты выбирали только по количеству возможностей, то, к примеру, относительно простые форматы вроде ini, json, toml и т.п. никто бы не выбирал, когда есть монструозные XML и YAML (это мне соседней темой навеяло, извиняюсь).

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

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

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

Я не сравнивал скалу и кресты с точки зрения замены

Тогда непонятно, зачем ты о ней вообще упомянул.

Это просто пример языка с широкими возможностями и без существенной боли

Так можно притянуть и F#, и Haskell, и даже C#.

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

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

Капитан никогда не был так очевиден.

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

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

Когда у тебя в руках молоток, все задачи кажутся гвоздями, да :D

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

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

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

Но речь не о всех задачах, а о тех, для которых C++ используется.

Для большинства таких задач Rust ничем не уступает С++.

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

Тут выше обсуждалось. Простейшую индексацию ассоциативного массива не сделать полноценно.

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

не сделать полноценно.

Хэй-хэй, твой пример со странным контейнером не был «Простейшей индексацией ассоциативного массива»)

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

Это был не мой пример. Ну назови как-нибудь иначе, суть не в этом. А если с детской задачей не справился rust, что же будет в реальной практике?

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

Чего в нем странного? Ожидаемое и очень удобное поведение. В Rust разве индексация не приведёт к вставке объекта, если его не было?

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

Не смеши, C# нормален только в оффтопике. Под Linux это жалкое поделие.

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

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

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

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

А в паскале есть нормальные модули? Я в последний год полюбил ML, модулями (особенно first-class) прекрасно разбивать большую программу на логические части, а уж библиотеку - сам Харпер велел

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

Чем на практике это отличается от хидеров и исходников, ну кроме времени компиляции?

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

К программистам тоже. Обоснуй. Я, например, обычно выбираю между питоном, С и C++. Под Android между Java, Scala и, опять же, C++. А ты как делаешь?

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

Я в последний год полюбил ML, модулями (особенно first-class) прекрасно разбивать большую программу на логические части

«Нормальных» (ML-подобных) модулей нет и в Rust.

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

Я выбираю язык, который мне нравится (субъективное понятие) и на котором я умею продуктивно работать и использую его. Если этот язык оказывается неудобным для моей задачи, я выбираю следующий язык по вышеуказанным критериям и так далее.

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

buddhist ★★★★★
()
Ответ на: комментарий от anonymous
use std::collections::TreeMap;
use std::default::Default;

trait Dict<K, V> {
    fn get<'a>(&'a mut self, key: K) -> &'a V;
    fn get_mut<'a>(&'a mut self, key: K) -> &'a mut V;
}

impl<K: Ord + Clone, V: Default> Dict<K, V> for TreeMap<K, V> {
    fn get<'a>(&'a mut self, key: K) -> &'a V {
        if !self.contains_key(&key.clone()) {
            self.insert(key.clone(), Default::default());
        }
        
        self.find(&key.clone()).unwrap()
    }

    fn get_mut<'a>(&'a mut self, key: K) -> &'a mut V {
        if !self.contains_key(&key.clone()) {
            self.insert(key.clone(), Default::default());
        }
        
        self.find_mut(&key.clone()).unwrap()
    }
}

struct My;

fn main() {
    let mut d1 = TreeMap::new();
    
    *d1.get_mut(0u) = "Hello, world!".to_string();
    
    println!("\"{}\"", d1.get(0));     // "Hello, world!"
    println!("\"{}\"", d1.get_mut(1)); // ""
    
    let mut d2: TreeMap<uint, My> = TreeMap::new();
    
    // Ok
    d2.insert(0, My);
    
    // error: failed to find an implementation of trait core::default::Default for My
    d2.get_mut(1);
}
anonymous
()
Ответ на: комментарий от buddhist

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

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

Два раза ищешь по дереву в get_mut в лучшем случае и три раза в худшем.

А get я могу вызывать для d2?

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

Два раза ищешь по дереву в get_mut в лучшем случае и три раза в худшем.

Детали реализации, мне лень делать лучше.

А get я могу вызывать для d2?

Если реализуешь трейт Default. Иначе, пользуйся find.

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