LINUX.ORG.RU

Стоит ли переписывать проект с Go на Rust?

 ,


0

5

Вот думаю, а не переписать бы мне out-of-tree на Rust? Последний я в некоторой степени знаю, но полноценных самостоятельных проектов пока не было. Пока проект не разжирел сильно (всего две с половиной тысяч строк), поэтому переписывание само по себе не будет слишком затратно по времени.

Какие преимущества я получу?

С какими проблемами я столкнусь?

Deleted

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

что лично вас, сидящих на LOR-е, отпугивает от паскаля

Почему сразу «отпугивает»? Он просто уныл.

На галерах с паскалем мест мало?

В том числе. Зачем ковырять унылый паскаль, если можно ковырять унылую жабку, например? За неё хоть платят.

no-such-file ★★★★★ ()
Ответ на: комментарий от no-such-file

что лично вас, сидящих на LOR-е, отпугивает от паскаля

Почему сразу «отпугивает»? Он просто уныл.

Что значит «уныл»? Слишком легко написать работающее приложение?

Зачем ковырять унылый паскаль, если можно ковырять унылую жабку, например? За неё хоть платят.

Да. За дотнет еще платят.

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

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

Не паскаль а ML. Первая версия компилятора раста была написана на OCaml. Оттуда и взяли и жесткую типизацию и алгебраические типы данных с паттерн матчингом и let присваивание и «все есть выражение» (функции без return) и функциональщину в итераторах.

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

therecipe/qt пробовал, конечно

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

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

Разберем написанное по частям

Первая версия компилятора раста была написана на OCaml.

На функциональных языках довольно удобно писать обработку логическо-языковых конструкций.

Оттуда и взяли и жесткую типизацию

Оттуда не «взяли» выведения типов, что является ключевой фичей всех ML языков. Да, раст может додумать тип по присваиванию внутри функции, но, извините меня, C++ тоже это делает. Основная идея выведения типа в функциональных языках ведь состояла в том, что сложная система функций компонуется без необходимости париться с типами передаваемых между ними значений.

и алгебраические типы данных с паттерн матчингом

Несмотря на отдаленную внешнюю схожесть конструкций в ML и Rust, на самом деле они не имеют ничего общего. В расте enum неявно хранит тэг с типом фактически хранимых данных, а match представляет собой switch по этому тэгу. По сути это безопасный вариант сишного struct{ enum... union {struct... struct...} }

и let присваивание

Если бы они использовали слово var/const, то было бы ПАЛЕВО, потому что тогда объявления бы один в один совпадали с паскалевыми. Кстати, это не присваивание, а объявление, которое опционально может быть совмещено с присваиванием. А паскаль возник на 3 года раньше ML.

«все есть выражение» (функции без return)

Функции без return - это еще далеко не выражение, это все еще по прежнему функции C.

функциональщину в итераторах

Ты про замыкания в качестве аргумента? Замыкания в Rust реализованы ужасно - это trait, который реализуется для структуры, содержащей локальные данные функции. Одно из следствий - ты не можешь вернуть из функции замыкание, которое использует локальную переменную возвращающей функции, потому что структура замыкания содержит ссылку на эту локальную переменную, а сама переменная лежит в стэке и компилятор жестко проверяет видимость переменных. Ну то есть весь смысл замыканий теряется, и по сути мы сидим на всё том же уровне C с его функциями, локальными переменными, и указателями на функции.

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

Оттуда не «взяли» выведения типов

В расте используется система типов Хиндли-Милнера, которая также используется в Haskell, и семействе ML

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

Замыкания в Rust реализованы ужасно - это trait, который реализуется для структуры, содержащей локальные данные функции. Одно из следствий - ты не можешь вернуть из функции замыкание

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

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

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

С move уже не важно, какое значение будет присвоено локальным переменным

Отсутствие неконтролируемого мутабельного алиасинга - основной принцип раста, так что ничего удивительного. Если хочется иметь замыкания как в js, используем Rc.

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

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

Отсутствие неконтролируемого мутабельного алиасинга - основной принцип раста, так что ничего удивительного. Если хочется иметь замыкания как в js, используем Rc.

Что такое Rc?

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

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

Точно такие же замыкания в C++. Такие они по единственной причине в обоих языках нет GC. Польза от таких замыканий ничем ни меньше чем в языках с GC, просто местами удобство использования меньше из-за того что надо следить за владением, но все равно это намного удобнее чем скажем городить функторы на каждый чих как это было в С++ до С++11.

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

В расте используется система типов Хиндли-Милнера, которая так же используется в Haskell, и семействе ML

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

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

Да, раст может додумать тип по присваиванию внутри функции, но, извините меня, C++ тоже это делает.

В C++ нет полноценного вывода типов по использованию, только по объявлению (ну и в шаблонах есть но там не вывод типов а наоборот). В раст полноценный вывод типов, но в отличии от ML языков не глобальный, только в пределах функции. Вот иллюстрация полноценности:

fn type_inference_tst() {
    let mut vec = Vec::new(); // здесь тип элемента вектора еще не задан.
    let text = "Message";
    vec.push(text); // здесь происходит вывод типа.
    println!("type_inference_tst: {:?}", vec);
}
В точке объявления вектора тип еще не известен, с++ так не может.

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

Отсутствие неконтролируемого мутабельного алиасинга - основной принцип раста, так что ничего удивительного. Если хочется иметь замыкания как в js, используем Rc.

Указатель с подсчетом ссылок

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

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

Польза от таких замыканий ничем ни меньше чем в языках с GC, просто местами удобство использования меньше из-за того что надо следить за владением, но все равно это намного удобнее чем скажем городить функторы на каждый чих как это было в С++ до С++11.

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

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

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

Куче типовых применений замыканий нисколько не мешает то что нужно следить за владением. Вот например одно из применений псевдообъект:

/*
    Проверка возврата счетчика в замыкании.
*/
fn gen_counter(n: i32) -> impl FnMut() -> Option<i32> {
    let mut count = 0;
    move || {
        let result = if count < n { Some(count) } else { None };
        count += 1;
        result
    }
}
//...
let mut c1 = gen_counter(4);
    while let Some(i) = c1() {
        println!("  i = {}", i);
    }

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

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

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

В раст полноценный вывод типов, но в отличии от ML языков не глобальный, только в пределах функции.

Ну, смотря с чем сравнивать. По сравнению с Хиндли-Милнером это неполноценный вывод, по сравнению с C++ - полноценный.

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

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

Ну да, можно вручную рисовать структуры со ссылками и функции, принимающие их как параметры, а можно вообще ничего не делать кроме mov: mov is Turing-complete.pdf, но будет ещё неудобнее. С заботой об удобстве это как-то плохо сочетается.

Кстати, в чём конкретно неудобство-то? Замыкания со ссылками на несуществующий фрейм стека позволять по понятным причинам нельзя.

Замыкания с захваченными расшареными ссылками (Rc, Arc) сделать тривиально.

Ещё больше удобства можно только с garbage collection.

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

Несмотря на отдаленную внешнюю схожесть конструкций в ML и Rust, на самом деле они не имеют ничего общего. В расте enum неявно хранит тэг с типом фактически хранимых данных, а match представляет собой switch по этому тэгу. По сути это безопасный вариант сишного struct{ enum... union {struct... struct...} }

В OCaml точно также неявно хранится тег и точно такой же switch. И в rust и в OCaml все это устроенно одинаково, вплоть до того что ПМ работает не только в match но и в let. И вообще функциональный код довольно легко переводится на раст.

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

while let Some(i) = c1()

Какой же вырвиглазный синтаксис, они все-таки переняли эти кошмарные конвееры с сей. Можно же сделать просто «while c1(i)»

Куче типовых применений замыканий нисколько не мешает то что нужно следить за владением. Вот например одно из применений - псевдообъект

Это не псевдообъект - это объект. Причем, как идейно, так и по фактической реализации - замыкание так работать не может. У объекта есть поля n и count, конструктор gen_counter, и безымянный метод.

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

Можно же сделать просто «while c1(i)»

Можно: for i in c1() {}. while let - это для общих случаев. А что должно значить while c1(i), я что-то не представляю. Функция c1 не принимает никаких параметров.

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

Если бы они использовали слово var/const, то было бы ПАЛЕВО, потому что тогда объявления бы один в один совпадали с паскалевыми. Кстати, это не присваивание, а объявление, которое опционально может быть совмещено с присваиванием. А паскаль возник на 3 года раньше ML.

Это не объявление, а привязка (binding) let раста полностью повторяет let Ocaml'а, можно переопределять переменную, можно использовать ПМ в let, по умолчанию переменная не мутируемая.

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

На функциональных языках довольно удобно писать обработку логическо-языковых конструкций

Вот только как правило компиляторы все равно не на окамлах пишут. Почему там был окамл и как это связано с дизайном языка - легко видно по истории.

Несмотря на отдаленную внешнюю схожесть конструкций в ML и Rust, на самом деле они не имеют ничего общего. В расте enum неявно хранит тэг с типом

У-у... Скажи проще, что ML ты не знаешь, а на паскале просидел много лет. Это объяснит, как в расте можно увидеть паскаль вместо ML.

Хотя, справедливости ради, ML и паскаль местами синтаксически и лексически схожи. Но не семантически.

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

Какой же вырвиглазный синтаксис, они все-таки переняли эти кошмарные конвееры с сей. Можно же сделать просто «while c1(i)»

Про кошмарные конвееры с сей можно уточнить что имеется в виду? К си эта конструкция отношения не имеет, это функциональщина, в раст есть конструкции if let ... и while let ... в которых условие выполняется если было успешное сопоставление с образцом, удобно если нужен только один вариант а не полноценный match.

Это не псевдообъект - это объект

Вспоминаю старые срачи функциональщиков что первично яйцо объект или замыкание :)

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

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

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

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

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

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

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

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

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

К сожалению, не знаком с крестами и ненавижу этот язык

Э... Скажите, а как можно ненавидеть то, с чем не знаком?

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

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

От того, что параметр self синтаксически скрыт, хоть и доступен - он никуда не исчезает.

Это в каких языках замыкание получает доступ к захваченным переменным без использования какой-то структуры данных для хранения значений/ссылок? С помощью функциональной магии надо полагать?

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

Сам же выше привел определение:

«Замыкание (англ. closure) в программировании — функция первого класса, в теле которой присутствуют ссылки на переменные, объявленные вне тела этой функции в окружающем коде и не являющиеся её параметрами.»

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

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

Кстати, в чём конкретно неудобство-то? Замыкания со ссылками на несуществующий фрейм стека позволять по понятным причинам нельзя

Неудобство в том, что это не замыкание. Как вложенная функция с неявными параметрами это вполне прокатывает. Второе неудобство заключается в том, что в этот же синтаксис засунули второе объявление объекта (анонимного типа), которое никак не похоже на обычный struct.

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

Неудобство в том, что это не замыкание.

Так, так. И как же правильно реализовать настоящее замыкание? С примером того в какой ассемблерный код это скомпилируется.

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

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

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

В OCaml точно также неявно хранится тег и точно такой же switch. И в rust и в OCaml все это устроенно одинаково, вплоть до того что ПМ работает не только в match но и в let. И вообще функциональный код довольно легко переводится на раст.

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

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

Я про модуль std::iter::Iterator https://doc.rust-lang.org/std/iter/trait.Iterator.html в котором реализованные практически все типовые ФВП функциональщины.

В крестах валом ФВП, даже в голом C их нередко используют. Другое дело, что объявление функции там побольше будет, потому менее очевидно и менее удобно.

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

А что должно значить while c1(i), я что-то не представляю. Функция c1 не принимает никаких параметров.

Сделать функции c1() аргумент, чтобы стало c1(i). Но вот эта дрянь «while (a==int b=c=d)» - это очень плохой стиль, особенно в языке, где операция присваивания записывается знаком равенстве.

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

Интересно где ты все это увидел? Можно продемонстрировать кодом на расте?

Выше код на расте создания анонимного объекта-счетчика Стоит ли переписывать проект с Go на Rust? (комментарий)

А без move это «замыкание» вообще нельзя вернуть из функции - будет ошибка компиляции.

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

На OCaml очень удобно писать прототип компилятора

Без вопросов. Только надо знать окамл, и создатели раста его знали хорошо.

и компиляторы написанные на OCaml вполне себе есть

Для какого-то собственного, специализированного языка - пожалуйста. А для открытого ЯП общего назначения?

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

И как же правильно реализовать настоящее замыкание? С примером того в какой ассемблерный код это скомпилируется.

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

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

case работает с выведением типов во время компиляции

Я бы очень советовал RTFM перед тем, как делать такие заявления.

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

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

На OCaml очень удобно писать прототип компилятора

Без вопросов. Только надо знать окамл, и создатели раста его знали хорошо.

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

и компиляторы написанные на OCaml вполне себе есть

Для какого-то собственного, специализированного языка - пожалуйста. А для открытого ЯП общего назначения?

Зависит от степени безбашенности разрабов. Питон на питоне уже написали, например. Так-то их цель была написать раст на расте, но нельзя написать раст на расте, когда у тебя нет раста.

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

Агаг, нагуглил кое что. «Создатели» выступали в единственном числе под именем Грейдон Хоар, и по мере расширения круга создателей оперативно спустили окамл в унитаз. Почему-то мне кажется, что современные «создатели» не умеют писать на окамле.

byko3y ()