LINUX.ORG.RU

Rust + C++ = Дружба на века

 ,


0

7

Тут Rust-C++ Interoperability Initiative

Проблема взаимодействия Rust и C++: Постановка задачи

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

В постановке задачи описаны три ключевых стратегических подхода:

  1. Улучшение существующих инструментов и решение тактических проблем в рамках проекта Rust для снижения трения и рисков при взаимодействии языков в краткосрочной перспективе.
  2. Достижение консенсуса по долгосрочным целям, требующим изменений в самом Rust, и разработка тактических подходов для их реализации.
  3. Взаимодействие с сообществом C++ и комитетом по стандартизации для улучшения качества взаимодействия обоих языков, что поможет достичь общих целей в области безопасности и производительности.

З.Ы. По ссылке так и не нашёл технических проблем, кроме каких-то абстрактных, аля, «все должно быть легко», «ничего дополнительно писать не надо (ну или совсем чуть-суть)», …

Зато пункт 3 просто бомба.

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

В Rust’е есть тип char. Он 4 байта как и wchar_t.

Но строка в rust - это не массив char-ов.

Строка в rust - это utf-8 строка, по которой ты можешь итерироваться посимвольно, а итератор будет тебе отдавать char.

Поэтому нет доступа по индексу в строке в rust.

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

Поэтому нет доступа по индексу в строке в rust.

Есть, надо просто знать как.

fn main() {
    let text = "подстрока";
    let substring: String = text.chars().skip(3).take(6).collect();
    println!("{}", substring);
}
Эта программа выведет подстроку из 6-ти символов начиная с 4-го (3 пропускаем).
$ ./substring
строка
$

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

А какая разница если подстроку всё равно можно получить?

Кстати, в Си подстроку тоже через функцию (wcsncpy()) получать надо:

#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>

int
main(int argc, char **argv)
{
    setlocale(LC_ALL, "");
    wchar_t text[] = L"подстрока";
    wchar_t *substring = (wchar_t *) malloc (7*sizeof(wchar_t));
    wcsncpy(substring, text + 3, 7);
    wprintf(L"%ls\n", substring);
    free(substring);
    return 0;
}

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

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

давно c++ в ядре появился? в играх c++ в 2010 начал использоватся

s-warus ★★★★
()
Ответ на: комментарий от saahriktu

Эта программа выведет подстроку из 6-ти символов начиная с 4-го (3 пропускаем).

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

fn main() {
    let text = "\u{0418}\u{0306}од - элемент с номером 53";
    let substring: String = text.chars().take(3).collect();
    println!("{}", text);
    println!("{}", substring);
}

Йод - элемент с номером 53
Йо        // Ожидалось Йод

А ещё добавь сюда корректное сравнение строк хотя бы, и вот тебе уже нужно тянуть какую-нибудь говнину вроде ICU, которая жирнее всей std вместе взятой. Юникод ужасен и уродлив, никем толком до конца не поддерживается. Есть только полноценный ASCII, ну и весь остальной мусор с опциональной поддержкой в разных условиях. Обожаю Юникод …

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

use unicode_normalization::UnicodeNormalization;

fn main() {
    let text = "\u{0418}\u{0306}од - элемент с номером 53";
    let textn = text.nfc().collect::<String>();
    let substring: String = textn.chars().take(3).collect();
    println!("{}", textn);
    println!("{}", substring);
}
$ ./target/debug/ruststrnormtest
Йод - элемент с номером 53
Йод
$
saahriktu ★★★★★
()
Ответ на: комментарий от AlexVR

Так а как ты получишь доступ, если символ от 1 до 4 байт? Хочешь прямой доступ, используй срезы, но сам думай какой символ где кончается. Или в вектор:

let s = "Привет";
let chars: Vec<char> = s.chars().collect(); // O(n)
println!("{}", chars[2]); // O(1)
LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 1)
Ответ на: комментарий от LightDiver

Так а как ты получишь доступ, если символ от 1 до 4 байт?

Так я вроде об этом же и говорил.

Я же о том, что строки в rust не решают многих задач.

Что-то отсутствует, например, про chars:

Iteration over grapheme clusters may be what you actually want. This functionality is not provided by Rust’s standard library, check crates.io instead.

Что-то экспериментально, например, round_char_boundary

Что-то требует велосипедов, например, chars().collect() или char_indices для запоминания позиций + get_unchecked.

Что-то далеко за пределами, например, разбиение на предложения или «слова».

В итоге получаем не намного лучше, чем std::string + utfcpp из плюсов.

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

Чем тебе вектор не нравится?

А про плюсы.. Ну смотри. Написал я утилитку на раст вчера: https://github.com/Vladgobelen/NSkbd

Тут тебе и вектор вон, работа с файлами, работа со строками. Работа с иксами.

Запустил вчера же на сутки. Запомнил потребление памяти. Через день глянул. Память не изменилась даже на байт. Вот ты такое встречал вообще?

Все что я когда либо писал на си, текло, как сучка. Нет, я конечно си даже близко не знаю. Но и раст вижу третий раз в жизни по сути.

Просто надо принять особенности языка. Сделать можно то, что хочешь, нужно понять - как.

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

Чем тебе вектор не нравится?

Так он же вне «обработки строк» в Rust. В Rust слишком долго хорошим тоном было написание fn foo(input_string: &str). И если использовать Vec<Char>, то на каждый чих надо будет писать не производительный foo(&String::from_iter(&v[from..to])). И т.д. и т.п.

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

В ситуации с патчем в ядро для DMA, я больше на стороне мантейнера. Хоть тот и сорвался, но патч говно.

Сей час же у меня волосы дыбом от:

Hey, folks. I’ve been working on an RFC for adding a limited form of C++ inheritance to Rust, including virtual methods. The goal is to enable direct interop with C++ code, allowing Rust code to call C++ virtual methods, and allowing Rust code to provide vtables that can be called directly by C++ code.

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

Если честно, не понял проблемы. Как со строгами, так и с с++.

fn main() {
    let s = "Допустим, у нас есть строка";

    let words: Vec<&str> = s.split_whitespace().collect();

    match words.get(1) {
        Some(word) => println!("2-е слово: {}", word),
        None => println!("Нет второго слова!"),
    }

    if words.len() > 1 {
        println!("2-е слово (без проверки): {}", words[1]);
    }
}

Что не так с векторами вообще? А то я работаю работаю, может я зря их использую или что?

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

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

а также хорошо поддерживает юникод из коробки

utf-8 -> utf-32 - это функция в пару десятков строк. Это всё, что есть в твоем расте из коробки

anonymous
()
И начал так: «Друзья! К чему весь этот шум?
Я, ваш старинный сват и кум,
Пришел мириться к вам, совсем не ради ссоры;
Забудем прошлое, уставим общий лад!
А я, не только впредь не трону здешних стад,
Но сам за них с другими грызться рад
И волчьей клятвой утверждаю,

Что я…» — «Послушай-ка, сосед,—
Тут ловчий перервал в ответ,—
Ты сер, а я, приятель, сед,
И волчью вашу я давно натуру знаю;
А потому обычай мой:
С волками иначе не делать мировой,
Как снявши шкуру с них долой».
И тут же выпустил на Волка гончих стаю.

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

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

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

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

Смотря что считать «базовыми задачами». Не всем нужна нормализация юникода. Там выше я пофиксил конкретный пример.

Это расходится с твоими словами

Во-первых, я говорил про типы строк. О том, что в C/C++ люди юзают char16_t*, char32_t*, QString,... и т.д., но не wchar_t *. В моих примерах на Rust'е выше я никаких дополнительных типов строк не притаскивал. Во-вторых, библиотеки типа ICU являются своего рода комбайнами и реализуют не только нормализацию юникодных строк. Библиотека, которая реализует только нормализацию юникодных строк, определённо, гораздо менее жирная.

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

О том, что в C/C++ люди юзают char16_t*, char32_t*, QString,… и т.д., но не wchar_t *.

Так wchar_t то ещё удовольствие с не ясным размером и нужный, разве что, для работы с виндовым апи.

QString - прекрасная кросплатформенная абтракция.

Ну а по аналогии с Rust в плюсах то же можно работать со страками, когда они хранятся в utf-8, а итерируются по кодепоинтам. Возьми старенький utfcpp, используй std::string_view для входящих строк, добавь fmtlib:

#include <string>
#include <iostream>
#include <string_view>

#include <utf8.h>
#include <fmt/format.h>

void example(std::string_view s)
{
    fmt::print("{}\n", s);
    auto p = s.begin();
    auto e = s.end();
    while (p != e)
    {
        auto ch = utf8::next(p, e);
        fmt::print("0x{:04x} ", (uint32_t)ch);
    }
    fmt::print("\n\n");
}

int main()
{
    example(u8"Hello, World!");
    example(u8"Привет, мир!");
    example(u8"你好世界!");

    return 0;
}
Hello, World!
0x0048 0x0065 0x006c 0x006c 0x006f 0x002c 0x0020 0x0057 0x006f 0x0072 0x006c 0x0064 0x0021

Привет, мир!
0x041f 0x0440 0x0438 0x0432 0x0435 0x0442 0x002c 0x0020 0x043c 0x0438 0x0440 0x0021

你好世界!
0x4f60 0x597d 0x4e16 0x754c 0x0021

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

Так wchar_t то ещё удовольствие с не ясным размером и нужный, разве что, для работы с виндовым апи.

Нет, это нормальные юникодные строки в т.ч. с возможностью итерации посимвольно без привлечения костылей. И в линуксах размер очень даже ясен - 4 байта, как и char в Rust'е. А кроссплатформенный софт не всем нужен. В линуксах работает - и ладно.

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

как и char в Rust’е.

Ещё раз, char в расте это 32-битное целое, а не wchar. И он не имеет отношения к строке в расте. Только к итератору. Строки в расте, это однобайтовый utf-8.

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

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

Нет, у них такого обязательства нет. Сейчас это просто достаточно вместимый тип, способный хранить любой символ из всех системных локалей. Ну т.е., например, я могу locale independent запросить список файлов или открыть файл с именем. Соотвественно, прежде всего апи ОС должно поддерживать wchar_t. Подозреваю, что планировали его как символ из глобальной кодировки, какой и являлся юникод в самом начале, когда просто хотели всунуть туда все алфавиты без всяких комбинаций. Мелкомягкие повелись на всё это и вкрутили wchar_t в свое апи, но их быстро провернули на кукане, когда начали добавлять всякие комбинации, говно, и CJK. В итоге потери соответсвия 1 кодпоинт == 1 символ, wchar_t api окончательно потеряло всякий смысл (чем это лучше utf-8? Такой же непредсказуемый поток байтов).

Фактически, wchar_t как концепия мертва, выродилось в говно. POSIX полностью забил, а мелкомягкие носятся со своим deprecated со времен UCS-2

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

Да. Ибо юзкейсы бывают разные. Да и из-за перегруженности юникода он нигде на 100% не поддерживается.

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

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

Фактически, wchar_t как концепия мертва

Плюсую:

    auto p = std::filesystem::path("🧟‍♂️🧟‍♀️.txt");
    std::ifstream f(p);

Вполне себе работает и онтопике и в оффтопике.

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

Аххахаха! О чем вы вообще тут спорите? Я тут внезапно осознал, что на Раст можно переписать ВСЕ! И переписал тг-бота с питона на раст. Потребление 6мб вместо 42мб питона. Ноль утечек. Вес 4мб против 11мб питона в сборке.

Ну каеф же. А вы о мелочах спорите.

Правда на си бот вообще 42кб, но там утечки и сложно все.

А работает бот как раз со строками. Читает сообщения от пользователей, сравнивает с белым списком. Если нет в списке - просит подтвердиться. Проверяет подтверждение. Вообще сложностей в упор не вижу.

https://github.com/Vladgobelen/NStgbR

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

Я тут внезапно осознал, что на Раст можно переписать ВСЕ!

у тебя бот на расте - 240 строк. это не «все». это хелловорд, вторая итерация.

пока ты используешь раст просто как скриптовый язычог.

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

Пока мой максимум - 36 тысяч строк аддон на луа для wow.

На 36 тысячах строк процедурного программирования я окончательно запутался вообще намертво и меня осенило - я осознал ООП. Теперь я переписываю его на ООП:

https://github.com/Vladgobelen/NSQC3

4-5 тыщ строк уже есть. Сойдет? На раст не могу, извиняй, ограничения - что дали. На раст только утилитки для своего использования.

Но угадай что было бы, если бы мне был доступен раст? (не, для начала я никогда бы не научился писать аддоны, но это лирика) Правильно, я бы писал его на раст, ибо раст прекрасен.

Да и какая разница при модульной структуре? Для чего нам дан ООП? Разделяй проект. Не важно какой модульты будешь перепиливать. Нужно добавить - добавляй метод. Хоть 100 строк, хоть 1000, хоть сто тысяч. При нормальном подходе это все маштабируется.

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

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

так раст и есть процедурное программирование с витаминкой в виде интерфейсов.

как запутаешься, приходи к нам в си++

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

Ненене. Я уже почти познал ООП в раст. Я через него отказался от наследования в луа и оптимизировал некоторые классы на композицию. Так реально удобнее.

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

Попробовал го.. Ну, тяжкие ощущения. Будто увидел кривую пародию на раст. Размеры бинарников больше итоговые, косяки те же, плюс свои. Есть тормознутый сборщик мусора. Синтаксис не настолько красив. Больше ручной работы. Меньше удобств отладки. Я еще поизучаю, но изначально не понравилось после раста.

Вообще сейчас все в сравнении с растом кажется кривоватым. В нем будто собрали все самое удобное для меня, а в других - то одного нет, то другого. Даже гуй на нем лучше делать. В тот же питон пришлось Qt5 запихать и он весь корявый ппц получился. А весит втрое больше.

В го тоже не нашел красивых гуев. Файн попробовал - слабенько. Тянуть тяжелые Qt опять же разве что. Потыкал разные - не то.

Чем больше ковыряю разные языки, тем больше нравится раст.

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

Питон+Qt: https://s.iimg.su/s/05/0XgCS6WXsMAriiwXxUiCnxuwmnLPv46pbmQvRnu4.jpg

Питон(tk): https://s.iimg.su/s/05/fN50yYvXM4LEkoHLGrnLezUCQed5Q4j9YcPYbmJb.png

Go(fyne): https://s.iimg.su/s/05/xfONgwaUMwaE9j5VDYEwi8MnzZKCuj4q8ZrsY089.png

Раст(egui) светлая тема: https://s.iimg.su/s/05/XvhsBQ5NFP6g7ZDg9SEZryNrlDPSUu74g7KHDLhN.jpg

Раст(egui) темная тема: https://s.iimg.su/s/05/RjWzpRXWACSSMFyXhn6D8v9F4Q7EngLDQvHEIQTZ.jpg

Оцени чисто эстетически. У раст это минимальный встроенный. У питона ебейшая по размерам и функциональности (казалось бы) кутя. У го тоже встроенное минималистичное, но оно скорее сравнимо с питоноским тк. Ну чуть лучше можно настроить. Это если не брать все, кроме гуевой части. Чисто внешне приятнее работать с растом, тот же egui прекрасен. Даже Qt вызывает больше отторжения и внешне и при работе своими нюансами. А уж размеры. А память.

Если раст это 6мб озу, то питон(tk) это 70 мб на старте и течет, как сучка. Питон с Qt это вообще от 150-200мб со старта озу.

Го это 8-15мб озу с минимализмом.

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

Это чисто ПЕРВЫЙ взгляд нуба, ни на что не претендующий. Как я со старта увидел эти языки для себя. Я могу полностью ошибаться.

Считай что у меня 2 проекта (считай скриптика) на расте, одна попытка работать с го с нуля и с пяток на питоне. Все.

А еще я попробовал работать с C++.. Это тихий ужас. Все минусы, которые я встретил в в питоне, расте и го, объединились в C++. С одной стороны неудобство работы, с другой отсутствие работы с модулями, с третьей синтаксис явно изобретенный не для гуманоидов итд итп. И даже то, что нет сборщика, это у него нихера не плюс, что самое смешное. Это прямая зависимость на твои руки. Единственный на ком я так и не смог сделать шаблон проекта: тупо застрял на зипе. Не смог найти модуль для работы с зипом рабочий. И все. Да и не стал особо искать пока. Позже им займусь, нужно основы изучать. Я не понимаю базы даже. Нужна теория.

LightDiver ★★★★★
()
Последнее исправление: LightDiver (всего исправлений: 2)