Swift против Rust — бенчмаркинг на Linux с (не)понятным финалом

    Привет, Хабр!

    Периодически посматриваю на Swift в качестве языка прикладного программирования для Linux — простой, динамичный, компилируемый, без сборщика мусора, а значит, теоретически, пригоден и для устройств. Решил сравнить его с чем-то таким же молодым и модным — например Rust. В качестве теста я взял прикладную задачу — парсинг и агрегация большого файла JSON, содержащего массив объектов. Исходники старался оформлять в едином стиле, сравнивал по 4-м параметрам: скорость исполнения, размер бинарника, размер исходника, субъективные впечатления от кодинга.

    Подробнее о задаче. Имеется файл JSON размером 100 Мб, внутри массив из миллиона объектов. Каждый объект представляет собой запись о долге — название компании, список телефонов и сумма долга. Одни и те же телефоны могут использовать разные компании, и по этому признаку их нужно сгруппировать, т.е. выделить реальных дебиторов, имеющих список названий, список телефонов, и суммарный долг. Исходные объекты «грязные», т.е. данные могут быть записаны в виде строк / чисел / массивов / объектов.

    Результаты бенчмаркинга меня озадачили. Подробности и исходные тексты — под катом.

    Исходный JSON:
    [
        {"company":"Рога и копыта", "debt": 800, "phones": [123, 234, 456]},
        {"company":"Первая коллекторская", "debt": 1200, "phones": ["2128506", 456, 789]},
        {"company":"Святой престол", "debt": "666", "phones": 666},
        {"company": "Казачий спас", "debt": 1500, "phones": [234567, "34567"], "phone": 666},
        {"company": {"name": "Шестерочка"}, "debt": 2550, "phones": 788, "phone": 789},
    ...

    Детали реализации


    Задача распадается на 4 стадии:

    1) Буферизованное посимвольное чтение файла, потоковый парсинг и выделение объектов из массива. Не стал заморачиваться поиском библиотек типа YAJL, ведь мы точно знаем что внутри массив, и выделить объекты можно путем подсчета открывающих и закрывающих фигурных скобок {}, благо что они ASCII, а не многобайтные Unicode. На удивление, не обнаружил в обоих языках функции посимвольного чтения из потока Unicode — полное безобразие, слава богу что парсеры JSON берут эту работу на себя, иначе пришлось бы велосипедить с битовыми масками и сдвигами.

    2) Cтроки-объекты, выделенные на стадии 1, передаем штатному парсеру JSON, на выходе получаем динамическую структуру (Any в Swift и JsonValue в Rust).

    3) Копаемся в динамических данных, на выходе формируем типизированную структуру:
    //source data
    class DebtRec {
        var company: String
        var phones: Array<String>
        var debt: Double
    }

    4) Агрегируем запись о долге — ищем по номеру телефона дебитора (либо создаем), и обновляем его атрибуты. Для чего используем еще 2 структуры:
    //result data
    class Debtor {
        var companies: Set<String>
        var phones: Set<String>
        var debt: Double
    }
    class Debtors {
        var all: Array<Debtor>
        var index_by_phone: Dictionary<String, Int>
    }

    Итоговых дебиторов храним в динамическом массиве (векторе), для быстрого поиска по телефону используем индексную хеш-таблицу, в которой для каждого телефона храним ссылку на дебитора. Упс… Помня, что Rust не поощряет хранение реальных ссылок (даже иммутабельных), используем вместо ссылки числовой индекс дебитора в массиве all — доступ по индексу дешевая операция. Хотя, конечно, если все перейдут на доступ по индексам и хешам, получим не приложение, а какую-то СУБД. Может Rust этого от нас и добивается?

    P.S.
    Мой код на Rust далек от идеального — например, много to_string(), тогда как правильнее было бы заморочиться со ссылками и временами жизни (хотя предполагаю, что умный компилятор сделал это за меня). Что касается Swift — код также весьма далек от совершенства, но ведь в этом и цель бенчмаркинга — показать как простой человек склонен решать задачи на том или ином языке, и что из этого получается.

    Результаты тестирования


    Проекты компилировались со стандартными опциями:
    swift build -c release
    cargo build --release


    Дебажная версия Rust показала чудовищную производительность в 86 секунд, возможно, честно отрабатывая мои to_string() (а может вообще в машинный код не переводила? <шутка>). Для Swift разница в дебажной и релизной версии оказалась незначительной. Сравниваем только релизные версии.

    Скорость чтения и обработки 1 млн. объектов
    Swift: 50 секунд
    Rust: 4.31 секунды, то есть в 11.5 раз быстрее

    Размер бинарного кода
    Swift:
    Сам бинарник 62 Kb, но библиотеки runtime — 9 штук на сумму 54,6 Мб (я считал только те, без которых программа действительно не запускается)
    Rust:
    Бинарник получился не маленким — 1,9 Мб, зато он один («lto=true» ужимает до 950 Кб, но компилирует существенно дольше).

    Размер исходного кода
    Swift: 189 строк, 4.5 Kb
    Rust: 230 строк, 5.8 Кб

    Впечатления от языка
    Что касается кодинга — бесспорно, Swift гладкий и приятный глазу, особенно в сравнении с «ершистым» Rust, и программы получаются компактнее. Я не буду придираться к мелочам, отмечу лишь те грабли, на которые наступил сам при изучении. Простите, могу быть субъективен.

    1) Именования объектов стандартной библиотеки Swift (а также Foundation) не так интуитивны и структурированы как в Rust, видимо по причине необходимости тащить наследие предков. Без документации порой сложно догадаться, какой метод или объект нужно искать. Перегруженные конструкторы конечно добавляют приятной магии, но данный подход, похоже, совсем не молодежный, и мне ближе принцип именования фабричных методов в Rust — from_str(), from_utf8() и т.д.

    2) Обилие унаследованных объектов + перегрузка методов в Swift облегчает возможность начинающему программисту выстрелить себе в ногу. Например, в качестве промежуточного буфера прочитанных из файла байт я сначала использовал Data(), который как раз требуется на вход парсеру JSON. Этот Data имеет те же методы, что и Array, т.е. позволяет добавлять байты, да и по сути это одно и то же. Однако, производительность с Data была в несколько раз (!) ниже, чем в нынешнем варианте с Array. В Rust разница в производительности между векторами и слайсами практически не ощущается, а API доступа настолько разные, что никак не перепутать.
    PS
    В комментариях — специалисты по Swift смогли ускорить код в несколько раз, но это уже магия профессионалов, тогда как Rust смогли ускорить только на 14%. Получается, что порог вхождения в Rust на самом деле ниже, а не выше, как принято думать, и злой компилятор не оставляет никакой свободы «сделать что-то не так».


    3) Опциональный тип данных Swift (а также оператор приведения типов) сделаны синтаксически более изящно, через постфиксы ?! — в отличие от неуклюжего растового unwrap(). Однако растовый match позволяет единообразно обрабатывать типы Option, Result, Value, получая, при необходимости, доступ к тексту ошибки. В Swift же в разных местах используется то возврат Optional, то бросок исключения, и это иногда сбивает с толку.

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

    5) В Rust встречаются кривые синтаксические конструкции, например если нужно проверить значение JSON на пустоту, приходится писать один из 2-х смешных бредов:
    if let Null = myVal {
        ...
    }
    match myVal {
        Null => {
            ...
        }
        _ => {}
    }

    хотя напрашиваются очевидные варианты:
    if myVal is Null {
        ...
    }
    if myVal == Option::Null {
        ...
    }

    Поэтому и приходится в библиотеках создавать кучу методов is_str(), is_null(), is_f64() для каждого enum-типа, что, конечно, жуткие синтаксические костыли.
    PS
    Судя по всему, это скоро починят, в комментариях есть ссылка на proposal.


    Резюме


    Так что же так тормозит в свифте? Разложим на стадии:

    1) Чтение файла, потоковый парсинг с выделеним объектов
    Swift: 7.46 секунд
    Rust: 0.75 секунд

    2) Парсинг JSON в динамический объект
    Swift: 21.8 секунд
    — это миллион вызовов: JSONSerialization.jsonObject(with: Data(obj))
    Rust: 1.77 секунд
    — это миллион вызовов: serde_json::from_slice(&obj)

    3) Преобразование Any в типизированную структуру
    Swift: 16.01 секунд
    Rust: 0.88 секунд
    — допускаю, что можно написать оптимальнее, но мой код на Rust такой же «тупой» как и на Swift

    4) Агрегация
    Swift: 4.74 секунд
    Rust: 0.91 секунд

    То есть мы видим, что в языке Swift тормозит все, и его надо сравнивать с системами типа Node.js или Python, причем я не уверен, в чью пользу будет бенчмаркинг. Принимая во внимание огромность рантайма — об использовании в устройствах вообще можно забыть. Получается, что алгоритм подсчета ссылок гораздо медленнее сборщика мусора? Тогда что, все учим Go и MicroPython?

    Rust — красавчик, хотя задача была слишком простой, и погружаться в ад заимствований и лайфтаймов не было необходимости. Конечно, было бы неплохо протестировать растовые Rc<> на предмет торможения, а еще хочется прогнать данный тест на Node, Go и Java, но жаль свободного времени (хотя, по моим прикидкам, Javascript будет медленнее всего в 2.5 раза).

    P.S.
    Буду благодарен растаманам и свифтерам за комментарии — что не так с моим кодом.

    Исходные тексты


    Swift:
    main.swift
    import Foundation
    
    let FILE_BUFFER_SIZE = 50000 
    
    //source data
    class DebtRec {
        var company: String = ""
        var phones: Array<String> = []
        var debt: Double = 0.0
    }
    //result data
    class Debtor {
        var companies: Set<String> = []
        var phones: Set<String> = []
        var debt: Double = 0.0
    }
    class Debtors {
        var all: Array<Debtor> = []
        var index_by_phone: Dictionary<String, Int> = [:]
    }
    
    
    func main() {
        var res = Debtors()
    
        var fflag = 0
        for arg in CommandLine.arguments {
            if arg == "-f" {
                fflag = 1
            }
            else if fflag == 1 {
                fflag = 2
                print("\(arg):")
                let tbegin = Date()
    
                let (count, errcount) = process_file(fname: arg, res: &res)
    
                print("PROCESSED: \(count) objects in \(DateInterval(start: tbegin, end: Date()).duration)s, \(errcount) errors found")
            }
        }
    
        for (di, d) in res.all.enumerated() {
            print("-------------------------------")
            print("#\(di): debt: \(d.debt)")
            print("companies: \(d.companies)\nphones: \(d.phones)")
        }
    
        if fflag < 2 {
            print("USAGE: fastpivot -f \"file 1\" -f \"file 2\" ...")
        }
    }
    
    
    func process_file(fname: String, res: inout Debtors) -> (Int, Int) {
        var count = 0
        var errcount = 0
    
        if let f = FileHandle(forReadingAtPath: fname) {
            var obj: Array<UInt8> = []
            var braces = 0
    
            while true {
                let buf = f.readData(ofLength: FILE_BUFFER_SIZE)
                if buf.isEmpty {
                    break //EOF
                }
                for b in buf {
                    if b == 123 { // {
                        braces += 1
                        obj.append(b)
                    }
                    else if b == 125 { // }
                        braces -= 1
                        obj.append(b)
    
                        if braces == 0 { //object formed !
    
                            do {
                                let o = try JSONSerialization.jsonObject(with: Data(obj))
                                process_object(o: (o as! Dictionary<String, Any>), res: &res)
                            } catch {
                                print("JSON ERROR: \(obj)")
                                errcount += 1
                            }
    
                            count += 1
                            obj = []
                        }
                    }
                    else if braces > 0 {
                        obj.append(b)
                    }
                }
            }
        } else {
            print("ERROR: Unable to open file")
        }
        return (count, errcount)
    }
    
    
    func process_object(o: Dictionary<String, Any>, res: inout Debtors) {
        let dr = extract_data(o)
        //print("\(dr.company) - \(dr.phones) - \(dr.debt)")
    
        var di: Optional<Int> = Optional.none //debtor index search result
        for p in dr.phones {
            if let i = res.index_by_phone[p] {
                di = Optional.some(i)
                break
            }
        }
        if let i = di { //existing debtor
            let d = res.all[i]
            d.companies.insert(dr.company)
            for p in dr.phones {
                d.phones.insert(p)
                res.index_by_phone[p] = i
            }
            d.debt += dr.debt
        }
        else { //new debtor
            let d = Debtor()
            let i = res.all.count
    
            d.companies.insert(dr.company)
            for p in dr.phones {
                d.phones.insert(p)
                res.index_by_phone[p] = i
            }
            d.debt = dr.debt
    
            res.all.append(d)
        }
    }
    
    
    func extract_data(_ o: Dictionary<String, Any>) -> DebtRec {
    
        func val2str(_ v: Any) -> String {
            if let vs = (v as? String) {
                return vs
            }
            else if let vi = (v as? Int) {
                return String(vi)
            }
            else {
                return "null"
            }
        }
    
        let dr = DebtRec()
    
        let c = o["company"]!
        if let company = (c as? Dictionary<String, Any>) {
            dr.company = val2str(company["name"]!)
        } else {
            dr.company = val2str(c)
        }
    
        let pp = o["phones"]
        if let pp = (pp as? Array<Any>) {
            for p in pp {
                dr.phones.append(val2str(p))
            }
        } 
        else if pp != nil {
            dr.phones.append(val2str(pp!))
        }       
    
        let p = o["phone"]
        if p != nil {
            dr.phones.append(val2str(p!))
        }        
    
        if let d = o["debt"] {
            if let dd = (d as? Double) {
                dr.debt = dd
            }
            else if let ds = (d as? String) {
                dr.debt = Double(ds)!
            }
        }
    
        return dr
    }
    
    main()


    Rust:
    main.rs
    //[dependencies]
    //serde_json = "1.0"
    
    use std::collections::{HashMap, HashSet};
    use serde_json::Value;
    
    const FILE_BUFFER_SIZE: usize = 50000;
    
    //source data
    struct DebtRec {
        company: String,
        phones: Vec<String>,
        debt: f64
    }
    //result data
    struct Debtor {
        companies: HashSet<String>,
        phones: HashSet<String>,
        debt: f64
    }
    struct Debtors {
        all: Vec<Debtor>,
        index_by_phone: HashMap<String, usize>
    }
    
    
    impl DebtRec {
        fn new() -> DebtRec {
            DebtRec {
                company: String::new(),
                phones: Vec::new(),
                debt: 0.0
            }
        }
    }
    impl Debtor {
        fn new() -> Debtor {
            Debtor {
                companies: HashSet::new(),
                phones: HashSet::new(),
                debt: 0.0
            }
        }
    }
    impl Debtors {
        fn new() -> Debtors {
            Debtors {
                all: Vec::new(),
                index_by_phone: HashMap::new()
            }
        }
    }
    
    
    fn main() {
        let mut res = Debtors::new();
    
        let mut fflag = 0;
        for arg in std::env::args() {
            if arg == "-f" {
                fflag = 1;
            }
            else if fflag == 1 {
                fflag = 2;
                println!("{}:", &arg);
                let tbegin = std::time::SystemTime::now();
    
                let (count, errcount) = process_file(&arg, &mut res);
    
                println!("PROCESSED: {} objects in {:?}, {} errors found", count, tbegin.elapsed().unwrap(), errcount);
            }
        }
    
        for (di, d) in res.all.iter().enumerate() {
            println!("-------------------------------");
            println!("#{}: debt: {}", di, &d.debt);
            println!("companies: {:?}\nphones: {:?}", &d.companies, &d.phones);
        }
    
        if fflag < 2 {
            println!("USAGE: fastpivot -f \"file 1\" -f \"file 2\" ...");
        }
    }
    
    
    fn process_file(fname: &str, res: &mut Debtors) -> (i32, i32) { 
        use std::io::prelude::*;
    
        let mut count = 0;
        let mut errcount = 0;
    
        match std::fs::File::open(fname) {
            Ok(file) => {
                let mut freader = std::io::BufReader::with_capacity(FILE_BUFFER_SIZE, file);
                let mut obj = Vec::new();
                let mut braces = 0;
    
                loop {
                    let buf = freader.fill_buf().unwrap();
                    let blen = buf.len();
                    if blen == 0 {
                        break; //EOF
                    }
                    for b in buf {
                        if *b == b'{' {
                            braces += 1;
                            obj.push(*b);
                        }
                        else if *b == b'}' {
                            braces -= 1;
                            obj.push(*b);
    
                            if braces == 0 { //object formed !
    
                                match serde_json::from_slice(&obj) {
                                    Ok(o) => {
                                        process_object(&o, res);
                                    }
                                    Err(e) => {
                                        println!("JSON ERROR: {}:\n{:?}", e, &obj);
                                        errcount +=1;
                                    }
                                }
    
                                count += 1;
                                obj = Vec::new();
                            }
                        }
                        else if braces > 0 {
                            obj.push(*b);
                        }
                    }
                    freader.consume(blen);
                }
            }
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
        return (count, errcount);
    }
    
    
    fn process_object(o: &Value, res: &mut Debtors) {
        let dr = extract_data(o);
        //println!("{} - {:?} - {}", &dr.company, &dr.phones, &dr.debt,);
    
        let mut di: Option<usize> = Option::None; //debtor index search result
        for p in &dr.phones {
            if let Some(i) = res.index_by_phone.get(p) {
                di = Some(*i);
                break;
            }
        }
        match di {
            Some(i) => { //existing debtor
                let d = &mut res.all[i];
                d.companies.insert(dr.company);
                for p in &dr.phones {
                    d.phones.insert(p.to_string());
                    res.index_by_phone.insert(p.to_string(), i);
                }
                d.debt += dr.debt;
            }
            None => { //new debtor
                let mut d = Debtor::new();
                let i = res.all.len();
    
                d.companies.insert(dr.company);
                for p in &dr.phones {
                    d.phones.insert(p.to_string());
                    res.index_by_phone.insert(p.to_string(), i);
                }
                d.debt = dr.debt;
    
                res.all.push(d);
            }
        }
    }
    
    
    fn extract_data(o: &Value) -> DebtRec {
        use std::str::FromStr;
    
        let mut dr = DebtRec::new();
    
        let c = &o["company"];
        dr.company =
            match c {
                Value::Object(c1) =>
                    match &c1["name"] {
                        Value::String(c2) => c2.to_string(),
                        _ => val2str(c)
                    },
                _ => val2str(c)
            };
    
        let pp =  &o["phones"];
        match pp {
            Value::Null => {}
            Value::Array(pp) => {
                for p in pp {
                    dr.phones.push(val2str(&p));
                }
            }
            _ => {dr.phones.push(val2str(&pp))}
        }
    
        let p = &o["phone"];
        match p {
            Value::Null => {}
            _ => {dr.phones.push(val2str(&p))}
        }
    
        dr.debt =
            match &o["debt"] {
                Value::Number(d) => d.as_f64().unwrap_or(0.0),
                Value::String(d) => f64::from_str(&d).unwrap_or(0.0),
                _ => 0.0
            };
    
        return dr;
    
        fn val2str(v: &Value) -> String {
            match v {
                Value::String(vs) => vs.to_string(), //to avoid additional quotes
                _ => v.to_string()
            }
        }
    }


    Тестовый файл.
    Поделиться публикацией

    Комментарии 438

      +1
      Сам бинарник 62 Kb, но библиотеки runtime — 9 штук на сумму 54,6 Гб (я считал только те, без которых программа действительно не запускается)

      Вы точно не ошиблись на 3 порядка? видимо, должно быть 54,6 Мб…
      Просто рантайм на 54 гига даже в наше время избыточно жирных программ это что-то запредельно избыточное…
        0
        Спасибо, поправил!
      +1
      Не могли бы вы выложить файлы с данными для парсинга, чтобы попробовать запустить у себя?
        +1
        Если не лень качать. В принципе это просто размноженный фрагмент, приведенный в статье. В консоль должно вывести 2 записи.
          0

          Добавте ссылку в статью. или ссылку на код которым этот файл сгенерирован.

      0
      Rust действительно красавчик. Вы сравнивали потребление памяти? Возможно set в свифте дерево и его некорректно сравнивать с хешмапой, ведь оно требует куда большего кол-ва памяти, а свифт создан «для мобилок».
        +1
        Swift — VSZ: 205 Мб, RSS: 21 Мб
        Rust — VSZ: 13 Мб, RSS: 1Мб
        Все стабильно, не течет.
        +6
        «Некрасивость» кода на Rust в приведенном примере возникла исключительно из-за стиля написания. Например, обработку ошибки при открытии файла на Rust можно было написать в точности таким же `if let`, как на Swift. То же самое относится и к match в проверках на None. И еще много таких мест есть. Кажется, если поправить их все, код на Rust будет даже более красивым.
          +3
          Согласен, недавно только понял, что деструктуризация if let Ok(o) = val нагляднее, чем у других, так как сразу виден тип переменной val.
            +6
            Eще в таких же случаях методы типа .and_then() могут быть полезны. Или возврат ошибки из функции через оператор "?" с переносом обработки ошибок на уровень выше.

            При чтении файла можно выкинуть всю возню с буферизацией и написать буквально так:
            `for byte in BufReader(file).bytes()`.

            Вместо `Option::None` можно писать просто `None`, так как это имя всегда импортировано. Аннотация типа в той же строке не нужна, Rust сам выведет. Вообще этот цикл лучше переписать как-то так:
            `let dr = di.phones.iter().map(|p| res.index_by_phone.get(p)).any(Option::is_some);`

            Тот же прием лучше использовать для итерирования по байтам: поскольку все непустые ветки завершаются одним и тем же `push()`, то имеет смысл профильтровать итератор, а потом вызвать `collect()`. Иногда такой подход повышает скорость, так как при заранее известном размере итератора вектор не будет переаллоцироваться.

            Еще во многих местах лишний match на String, так как `val_to_str()` уже содержит точно то же самое. Вместо `to_string()` почти везде можно писать `into()`. В целом, кажется, я могу раза в два сократить написанное тут. И это даже если не вспоминать, что крейт `serde` содержит готовую работу с JSON, и вообще всю программу можно свести к одному вызову `from_str()`, если добавить `#[derive(Deserialize)]` к структурам. По скорости это будет очень быстро, Deserialize не делает лишних копирований и прочего.

            Для переделки со строк на ссылки скорее всего достаточно просто сменить тип поля в структурах: сложная игра со временами жизни тут не требуется, достаточно просто формально это время объявить.
              +2
              Матч на стринг не лишний, если просто написать to_string(), то serde для строковых данных выведет еще дополнительные кавычки. За все остальное — большое спасибо!
                +1

                Кавычки внутри кавычек? Если так, то это где-то еще баг, и решать надо не таким способом. serde не дает дополнительных кавычек (точно знаю, у нас в продакшн он как раз на JSON). Если речь о скобках, не о кавычках, так там #[flatten] ставится. Чуть попозже внимательно проверю, откуда что идет, при беглом прочтении не вижу.

                  +2
                  Возможно это особенность реализации to_string() в serde_json::Value, похоже оно предназначено для презентационных целей, добавляет [], {}, "", надо просто другой метод исользовать.
                +1
                При чтении файла можно выкинуть всю возню с буферизацией и написать буквально так:
                `for byte in BufReader(file).bytes()`.
                =============
                Неа, полученный байт придется анрапить, а это задержка существенная, проверял. Проще вообще читать сразу из File, своим собственным буфером, как товарищ ниже мой код переделал.
            +3

            Что бы чуть-чуть поменьше кода получилось в раст версии можно убрать impl Struct блоки и заменить из на:


            #[derive(Default)]
            struct Debtor { /*... */ }
            // ...
            Debtor::default();

            Думаю, что было бы справедливо использовать тип process_file -> (isize, isize) или в swift поменять на Int32.


            Ещё чисто из эстетических соображений убрать вложеность match std::fs::File::open(fname).


            Возможно для swift версии будет иметь значение замена class на struct и соотвествующая замена let на var?

              +1
              Спасибо, не знал что дерайв дефолт и коллекции умеет инициализировать.
              Структуры в Swift передаются по значению, копированием, поэтому только классы.
                +3

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

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

                  Это не совсем так (точнее не всегда). Структуры в Swift используют семантику copy-on-write. То есть, в коде вида
                  let struct = Struct(var: 5)
                  var struct2 = struct
                  struct2.var = 10
                  

                  структура скопируется не на 2 строке, а на 3. Также есть ключевое слово inout, которое используется для передачи внутрь метода структуры через аргумент и модификации её без копирования.

                  Собственно, для изменения вашего кода с классов на структуры, мне понадобилось добавить всего 1 строку помимо замены ключевого слова class на struct. По производительности мне это обошлось в 1 копирование в методе process_object (и то я не увидел никакой разницы).
                –7
                Вы сравнили ежа с ужом, как минимум языки под разные задачи, тогда уж сравнивайте C++ и java, результат будет похожий.
                  +3
                  Как-то писал похожий бенч Go vs Javascript (V8), там разница 2.5 раза всего, на Java давно не писал, не знаю.
                    +2
                    А если попробовать более по свифтовому?

                    import Foundation
                    
                    struct DebtRec: Decodable {
                        private enum Key: String, CodingKey { case company, debt, phones }
                        private struct Company: Decodable { let name: String }
                        
                        enum Error: Swift.Error { case invalidCompany, invalidPhones, invalidPhoneItem, invalidDebt }
                        
                        let company: String, phones: [String], debt: Double
                        
                        private struct PhoneItem: Decodable {
                            let value: String
                            init(from decoder: Decoder) throws {
                                let decoder = try decoder.singleValueContainer()
                                guard let value = (try? decoder.decode(Int.self)).map({ "\($0)" }) ?? (try? decoder.decode(String.self)) else { throw Error.invalidPhoneItem }
                                self.value = value
                            }
                        }
                        
                        init(from decoder: Decoder) throws {
                            let container = try decoder.container(keyedBy: Key.self)
                            guard let company = (try? container.decode(String.self, forKey: .company)) ?? (try? container.decode(Company.self, forKey: .company).name) else { throw Error.invalidCompany }
                            self.company = company
                            guard let phones = (try? container.decode(Int.self, forKey: .phones)).map({ ["\($0)"] }) ?? (try? container.decode([PhoneItem].self, forKey: .phones).map({ $0.value })) else { throw Error.invalidPhones }
                            self.phones = phones
                            guard let debt = (try? container.decode(Double.self, forKey: .debt)) ?? (try? container.decode(String.self, forKey: .debt)).flatMap({ Double($0) }) else { throw Error.invalidDebt }
                            self.debt = debt
                        }
                    }
                    
                    func main() throws {
                        let data = try Data(contentsOf: URL(fileURLWithPath: "__path_to_json__"))
                        let res = try JSONDecoder().decode([DebtRec].self, from: data)
                    }
                    
                    try main()
                      +3
                      Не, ну так не честно.
                      VSZ: 1Гб
                      RSS: 920 Мб
                      Вы забрали весь файл в память, а в жизни приходится миллиарды записей обрабатывать.
                        +1
                        Это как бы решение из коробки, очевидно перед разработчиками swift не стояла задача супер оптимизации, в rust как известно наоборот.
                          +1
                          Ну, в общем, да. В браузере вообще невозможно файл потоково прочитать, и приходится ради такой мелочи ноду ставить :)
                            +2

                            В расте тоже есть решение из коробки let val = serde_json::from_str(file), только сравниваем мы вроде не стандартные функции работы с JSON, а более-менее эквивалентный код.

                              +2
                              Почему бы нам тогда не сравнить эквивалентный код на C++ и Java, и не порадоваться какой молодец C++?
                                +1

                                Напишите, почему бы и нет? Чем больше сравнений, тем лучше.

                                  –3
                                  Там где java, с++ вообще не котируется и наоборот. По этому это Вы напишите, а мы почитаем.
                            0

                            А что мешает «по-честному» декодировать таким же способом, но построчно или чанками из буфера?

                        +5
                        C++ проиграет, если на Rust писать чисто. Потому что на ту игру со ссылками, которая нормальна в Rust с его borrow checker, ни один программист C++ в здравом уме не решится и будет копировать строки.

                        Сравнение Rust и Swift более чем корректно, потому что это очень похожие по синтаксису языки. Компилятор Swift мог бы быть таким же быстрым, как Rust, если бы его разработчики не халтурили.
                          +1
                          Насколько я понимаю, в свифте любые указатели это Arc<>, может поэтому и тормоза.
                            +1
                            Свифт ни разу не позиционируется как самый быстрый, и корректнее было бы его сравнивать с Kotlin Native, тот вроде тоже с ARC и под мобилки.
                              –16
                              C++ проиграет, если на Rust писать чисто.

                              Везде и всюду видно обратное и именно поэтому rust целиком и полностью С/С++-зависим.

                              ни один программист C++ в здравом уме не решится и будет копировать строки.

                              И что же мне помешает? Что мешает другим? Везде и всюду не копируются, а тут вдруг кто-то сообщают обратное.

                              К тому же, раст состоит целиком и полностью из копирования. Там копируется всё и единственное, что ему позволяет существовать — это llvm и его оптимизации, которые выпиливают все эти копирования.

                              Сравнение Rust и Swift более чем корректно, потому что это очень похожие по синтаксису языки.

                              Неверно. Раст целиком и полностью состоит из костылей из которых не состоит тот же свифт, та же жава, сишарп — тысячи их. Как минимум там нет исключений, а значит он никому ненужен.

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

                              Именно компилятор раста халтура, ведь раст существует только благодаря халяве, которую даёт llvm(т.е. С++). У раста вообще нет никакого компилятора — есть огрызок фронта, который так же завязан на llvm-рантайме.

                              Для понимания всей нелепости раста без халявы — достаточно взглянуть на код «без оптимизаций» — это то, что генерирует «компилятор» раста. Хотя об этом я уже говорил выше.
                                +7
                                Везде и всюду видно обратное и именно поэтому rust целиком и полностью С/С++-зависим.

                                Каким образом раст С-зависим? Ну не считая всяких врапперов, но это про любой язык сказать можно.


                                И что же мне помешает? Что мешает другим? Везде и всюду не копируются, а тут вдруг кто-то сообщают обратное.

                                Тут вкратце, почему не получится. Если в двух словах, то в плюсах это будет очень хрупко, и буст по перфомансу не окупит потенциальных проблем.


                                Неверно. Раст целиком и полностью состоит из костылей из которых не состоит тот же свифт, та же жава, сишарп — тысячи их. Как минимум там нет исключений, а значит он никому ненужен.

                                Ха-ха


                                Именно компилятор раста халтура, ведь раст существует только благодаря халяве, которую даёт llvm(т.е. С++). У раста вообще нет никакого компилятора — есть огрызок фронта, который так же завязан на llvm-рантайме.

                                Это плохо?

                                  0
                                  Тут вкратце, почему не получится.

                                  Эм… Не понял, в чем проблема. «If I wished to use a pointer I would need to be sure that the vector isn’t deallocated by the time I’m done with it» — для этого есть умные указатели. «And more importantly, to be sure that no other code pushes to the vector (when a vector overflows its capacity it will be reallocated, invalidating any other pointers to its contents)» — так не надо пихать в вектор сами строки, пихай туда указатели на строки в куче, resize вектора никак не повлияет на указатели на сами объекты. Более того, std мир не ограничивается, есть другие реализации, например, Qt с его implicit sharing, там копирование объектов из-за этого дешевое потому, что самого копирования там как такового нет (пока ты не захочешь изменить одну из копий), причем все это реализовано абсолютно прозрачно. В общем, странно мне это читать, это из разряда страшилок скорее.
                                    +3

                                    Умные указатели требуют затрат в рантайме. Поэтому на плюсах приходится выбирать между быстрыми сырыми указателями и медленными умными.

                                      –1
                                      Зато они работают везде, а не только в пределах вашего собственного кода.
                                        0

                                        Возвращаю вам ваш аргумент: и как же они будут работать, если владелец объекта — внешняя dll? :-)

                                          0
                                          Эм… Куча-то у них общая, почему бы им и не работать?
                                            0

                                            Потому что внешняя dll в ситуации "codebase, так сказать, неполная" может удалить объект наплевав на все ваши умные указатели.

                                              –7
                                              А еще она может сделать rm -rf /. Ладно, в общем, вы скатываетесь в ту же демагогию, что и автор оригинальной статьи по ссылке, мне это не интересно. Просто имейте в виду для себя — когда вы пропагандируете rust, не делайте это так топорно. Для начинающих ваши аргументы могут показаться привлекательными, но для людей с опытом они выглядят… топорно и пропагандистски в плохом смысле. Я где-то понимаю, почему veslemay так хейтит пропагандистов rust'а :)
                                          +1
                                          То ли дело плюсы, там даже в пределах вашего собственного кода собранного разными версиями компилятора нихрена не гарантируется.
                                        +1
                                        для этого есть умные указатели

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


                                        так не надо пихать в вектор сами строки, пихай туда указатели на строки в куче

                                        Что значит "не пихайте сами строки"? Строки это и так указатели на кучу где лежат данные, в лучшем случае они еще и длину хранят.


                                        если есть такая опасность, то никто не мешает хранить в векторе такие же shared_ptr на атрибуты

                                        Даже если использовать shared_ptr через shared_ptr отстрелить ногу вполне себе легко можно:


                                        #include <memory>
                                        #include <iostream>
                                        #include <functional>
                                        
                                        std::function<int(void)> f(std::shared_ptr<int> x) {
                                            return [&]() { return *x; };
                                        }
                                        
                                        int main() {
                                            std::function<int(void)> y(nullptr);
                                            {
                                                std::shared_ptr<int> x(std::make_shared<int>(4));
                                                y = f(x);
                                            }
                                            std::cout << y() << std::endl;
                                        }
                                          –1
                                          А вы их используете для каждой переменной?

                                          Нет, конечно. Но автор же беспокоится, что в large codebase некий код где-то там far far away, который, возможно, и не он сам писал, может как-то что-то прощелкать в плане времени жизни. Для таких случаев использование умных указателей безусловно оправданно.

                                          Что значит «не пихайте сами строки»? Строки это и так указатели на кучу где лежат данные, в лучшем случае они еще и длину хранят.

                                          Ну я не знаю, что автор тут имел в виду под «when a vector overflows its capacity it will be reallocated, invalidating any other pointers to its contents», видимо, он пытается сделать что-то вроде std::vector<std::string> (а потом брать ссылки на элементы вектора) вместо std::vector<std::string*>, в общем, выглядит это либо как бред начинающего, либо как передергивание.
                                            +1
                                            std::vector<std::string*> это потенциально тормоза из-за нарушения локальности данных, а это кэш промахи и вот это вот все. Строчки же еще имеют оптимизацию, когда для коротких строк символы будут лежать внутри самого объекта, а не где-то в куче. Да и вообще, не принято в плюсах хранить указатели в контейнерах, если только это реально не нужно прямо кровь из носа. Причин для этого масса, помимо локальности данных.

                                            Автор ведет речь о слайсах, когда мы создаем указатель с длиной на внутреннее хранилище контейнера. Прямо как string_view, который все так долго ждали в плюсах. Только вот проблема, даже с учетом иммутабельности std::string мы с этими string_view запросто можем получить все вкусности плюсов — dangling pointer и use after free. А с std::vector дело еще хуже, ибо контейнер изменяемый и внутренний буфер могут внезапно уничтожить и реаллицировать в другом месте.

                                            Поэтому и хвалит он раст, у которого компилятор не позволит такой баг допустить. В других языках такие вещи решаются всякими сборщиками мусора. В плюсах это решается внимательными программистами и фиксами CVE, когда неизбежно что-то внимательный программист пропустит.
                                              0
                                              Строчки же еще имеют оптимизацию, когда для коротких строк символы будут лежать внутри самого объекта, а не где-то в куче.

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

                                                Почитайте про short string optimization.

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

                                                У него не требование, а факт того, что есть такая угроза и плюсы с ней никак не помогают. Раст помогает и ошибки допустить не позволит.
                                                  –1
                                                  Почитайте про short string optimization.

                                                  Вы… это самое… сами почитайте, о чем я пишу вообще.

                                                  Раст помогает и ошибки допустить не позволит.

                                                  Вы сильно преувеличиваете возможности компилятора раста что-то там «не позволить».
                                                    0
                                                    Вы… это самое… сами почитайте, о чем я пишу вообще.

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

                                                    Вы сильно преувеличиваете возможности компилятора раста что-то там «не позволить».

                                                    Пустые слова. Раст не позволит, плюсы позволят. Так эти языки работают.
                                                      0
                                                      Я это вижу

                                                      Не похоже.

                                                      Пустые слова. Раст не позволит, плюсы позволят. Так эти языки работают.

                                                      Пустые слова — это считать компилятор раста серебряной пулей, способной заглядывать внутрь сисколлов или сторонних библиотек без прилагаемых исходников.
                                                        0
                                                        Поэтому у растаманов и принято линковать все статически с lto, а сошки это моветон.
                                                          –1
                                                          Ессессно. Им пока везет, что они тихо-мирно варятся там в своем растамирке, где нет необходимости решать реальные задачи с помощью сторонних closed source библиотек, а также делать свои такие же closed source библиотеки на продажу.
                                                0
                                                Прямо как string_view, который все так долго ждали в плюсах.

                                                Все его использовали ещё со времён. Где именно его ждали? В стандарте? Ну слайсы для раста уже 10лет ждут в стандарте, как всё остальное.

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

                                                Как? Не даст взять ссылку на элемент и придётся(как автор делал) хранить индексы? Это неудобно, но ладно.

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

                                                Это одна из фундаментальные проблем «безопасности» подобного рода. Эта безопасность защищает даже тогда, когда никакой защиты ненужно. Но продолжает вносить оверхед(как и по производительности, так и по удобству программиста).
                                          0
                                          P.S. Прочитал там сносочку, кто-то рассказал гражданину про shared_ptr, но он начал придумывать новые страшилки — про «iterator invalidation» (пока ты держишь подконтрольную тебе копию shared_ptr, указывающую на вектор, вектор никуда не денется, и, соответственно, никакого iterator invalidation не будет), «someone consuming the API might take a reference of an attribute and hold on to it long enough for it to become invalidated» — если есть такая опасность, то никто не мешает хранить в векторе такие же shared_ptr на атрибуты: пока ты им владеешь, атрибут никуда не денется, даже если вектор будет полностью уничтожен. Например, такой код:

                                          auto func()
                                          {
                                              std::vector<std::shared_ptr<std::string>> vctor;
                                          
                                              vctor.push_back(std::make_shared<std::string>("FYVA"));
                                          
                                              return vctor.back();
                                          }
                                          
                                          int main()
                                          {
                                              auto res = func();
                                          
                                              std::cout << *res << std::endl;
                                          
                                              return 0;
                                          }
                                          

                                          вполне себе успешно выведет «FYVA», хотя контейнер, содержавший строку, уже был уничтожен на момент вывода.

                                          Более того, это будет совершенно безопасно работать даже в чужом коде, который доступен тебе исключительно в виде .lib/.so/.dll (насколько я понимаю, расту для его compile-time borrow checking нужен доступ к исходникам, ничего прочекать в чужом машинном коде он не в состоянии).

                                          Это не говоря уж о том, что в том же Qt этот атрибут (если это какой-то стандартный QString или контейнер (QList/QMap/...) или даже какой-то кастомный наследник от QObject с реализованной implicit sharing функциональностью, это несложно) можно будет просто скопировать локально через обычный конструктор копии или operator=(), и не париться — будет shallow copy.

                                          В общем, если по чесноку, аргументы автора выглядят, мягко говоря, надуманными и действительно похожими на пропаганду в плохом смысле этого слова.
                                            +2
                                            Iterator invalidation это про другое.

                                            #include <iostream>
                                            #include <vector>
                                            
                                            int main()
                                            {
                                                std::vector<int> a;
                                                a.push_back(1);
                                                a.push_back(2);
                                                for (int &b: a) {
                                                    a.push_back(b);
                                                }
                                                std::cout << "Hello, UB!\n";
                                                for (int &b: a) {
                                                    std::cout << b << "\n";
                                                }
                                            }
                                            


                                            Этот код компилируется без ошибок и предупреждений в GCC 4.9 c -Wall -Wextra -Wpedantic и выводит:

                                            Hello, UB!
                                            1
                                            2
                                            1
                                            0


                                            Некоторые операции над структурами инвалидируют итераторы, указывающие на эту структуру. Если после этого всё-таки использовать эти итераторы, то получаем undefined behavior.

                                            Очень рекомендую проверить свой код на такие случаи.
                                              0

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

                                                0

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

                                                  –2
                                                  Ну вот не надо про это, что «компилятор следит». Что ваш компилятор сделает, если владелец контейнера — чужая .dll, к коду которой у вас нет доступа (а это совершенно рядовая ситуация, с которой сталкивается любой разработчик сплошь и рядом)? Ничего он не сделает и не проверит.
                                                    0

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

                                                      0
                                                      Речь не идет о «двух локальных переменных». Автор сам пишет, что, дескать, «for a smaller codebase this might be possible» просто добавить в структуру указатель на вектор, но вот если codebase большая, дескать, то будут проблемы. А если codebase не просто большая, а еще и, так сказать, неполная?
                                                        +1

                                                        Если в документации на внешнюю dll не указано никакой информации о времени жизни своих объектов — такой dll, по-хорошему, вообще нельзя пользоваться.

                                                      0

                                                      Чужая dll это ансейф, и тут все то же самое, что в плюсах.


                                                      А где не ансейф, там гарантии работают.


                                                      Аргумент из разряда "а что если в компьютер с вашей программой прилетит метеорит".

                                                        0
                                                        Я к тому, что если вы пишете, прости господи, библиотеку, предоставляющую некий API, которую будут использовать как dll и, скорее всего, никто из использующих ее не будет ее каждый раз пересобирать, то вот эти вот все аргументы «а вдруг someone consuming the API might take a reference of an attribute and hold on to it long enough for it to become invalidated» — это как бы так себе аргумент, мягко говоря. Тут либо давать доступ к атрибутам через что-то вроде умных указателей, либо просто надеяться на то, что пользователи библиотеки напишут свой код аккуратно. Я думаю, в глубине души вы это и сами понимаете.
                                                          +1

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


                                                          Только это пессимистичный сценарий.


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

                                                            0
                                                            Если библиотека написана так, что ее функции принимают и возвращают умные указатели, то в «копии на всякий случай» смысла нет. Это лишний расход ресурсов.

                                                            Я помню функцию forEach, в которой в реализации копировался итерируемая коллекция, чтобы работало в случае инвалидации

                                                            Если эта forEach рассчитана на вызов чего-то внешнего, что ты в общем случае контролировать не можешь, то копирование — да, разумная предосторожность, что на C++, что на расте. foreach из Qt (который Q_FOREACH), например, по-любому делает shallow copy итерируемого контейнера, но там, как я уже писал, все продумано, и это дешевая операция. Если автор кода, который вызывается из foreach, молодец — то практически никаких затрат не будет, если не молодец — ну, будет дополнительное копирование.
                                                              0

                                                              Библиотека обычно написана в стиле ANSI C, потому что это единственный популярный язык со стабильным ABI. Откуда там возьмутся умные указатели — загадка.




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

                                                                0
                                                                Библиотеки разные бывают. Использовать ANSI C там никто не заставляет. Там может потребоваться собирать определенным компилятором, это да. А «обычное приложение» в моей практике сплошь и рядом линкуется к «непонятным либам», например, к Google AdMob, Firebase, Facebook SDK, и так далее.
                                                                  0
                                                                  Библиотеки разные бывают. Использовать ANSI C там никто не заставляет. Там может потребоваться собирать определенным компилятором, это да.

                                                                  За пределами плюсов им собственно мало кто пользуется. Если я хочу из C# вызвать библиотечные функци апи с умными указателями мне никак не поможет.


                                                                  А «обычное приложение» в моей практике сплошь и рядом линкуется к «непонятным либам», например, к Google AdMob, Firebase, Facebook SDK, и так далее.

                                                                  Да пожалуйста


                                                                  https://www.nuget.org/packages/Google.Apis/


                                                                  https://www.nuget.org/packages/Facebook
                                                                  ...

                                                                    0
                                                                    Я к тому, что если у компилятора раста нет доступа к коду этих «непонятных либ» (хотя бы в виде IL), он вряд ли сможет что-то там прочекать с временем жизни объектов, передаваемых в них или возвращаемых из них. Даже если сами эти библиотеки будут написаны на Rust, а потом собраны в .dll, это никак им не поможет. Привет, unsafe.
                                                                      +1

                                                                      Эмм, если мы на плюсах подключаем С++ либы, то на расте мы подключаем раст либы. Если либа написана на расте, то компилятор её уже провалидировал.


                                                                      Я не понимаю поинта.

                                                                        0
                                                                        Внутри она, возможно, и провалидирована, но вот в этой библиотеке, скажем, есть экспортированная функция, которая возвращает указатель на что-то. Компилятор в момент сборки этой библиотеки не может знать, как дальше этот указатель будет использован, и не может проверить, какое у него будет время жизни.
                                                                          0

                                                                          Валидировать время жизни указателя будет, очевидно, компилятор при сборке приложения, которая эту библиотеку использует. Библиотеке само собой об этом знать не нужно. Инкапсуляция, все дела.

                                                                            0
                                                                            Очевидно, он не сможет этого сделать без исходного кода библиотеки в том или ином виде. Исходники коммерческих библиотек никто раздавать, само собой, не будет ради этого.
                                                                              0
                                                                              Ничего не понял. Если либа возвращает растовую ссылку, то владелец этой ссылки должен быть не в либе, а в коде, использующем либу — он владельца и прибъет. Разве может быть ситуация, что из либы возвращается ссылка, и владелец этой ссылки сидит внутри либы? У меня компилятор ругается, что «объект не живет долго».
                                                                                –4
                                                                                :))) Да ужж, при таком подходе забавно было бы посмотреть на чисто растовский аналог обычной библиотечной функции для работы с памятью типа malloc(). Для библиотек вообще-то создавать некие свои ресурсы и возвращать на них указатели или хэндлы для дальнейшего использования в этой же библиотеке (а затем и освобождения) — это нормальная практика. Не всегда можно требовать, чтобы владелец ссылки в коде, использующем либу, вообще был в курсе, сколько памяти нужно выделить под соответствующий объект, например. Не его это собачье дело.

                                                                                P.S. И, кстати, что такое «владелец»? В графе, например, или в двусвязном списке, кто чей владелец?

                                                                                P.P.S. Растаман у меня (сорри, конечно, но не могу удержаться) ассоциируется с человеком в смирительной рубашке в кресле-каталке, который ходит ездит не туда, куда ему нужно, а туда, куда повезет санитар, но зато счастлив, что не может случайно упасть и ушибить коленку. При этом вероятность разбить коленку по факту все равно никуда не девается потому, что это в любой момент могут сделать многочисленные окружающие.
                                                                                  0
                                                                                  PsyHaSTe более компетентен в расте, насколько моих знаний хватает — любая функция может вернуть либо копию данных, либо указатель на память, выделенную до вызова этой функции, возможно есть исключения, не знаю.
                                                                                  Графы и списки — это ж известный траходром раста, там специальные контейнеры для этого запилили :)
                                                                                    0
                                                                                    любая функция может вернуть либо копию данных, либо указатель на память, выделенную до вызова этой функции, возможно есть исключения, не знаю.

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

                                                                                    Графы и списки — это ж известный траходром раста, там специальные контейнеры для этого запилили :)

                                                                                    Не удивлен вообще нисколько.
                                                                                    +1
                                                                                    Да ужж, при таком подходе забавно было бы посмотреть на чисто растовский аналог обычной библиотечной функции для работы с памятью типа malloc().

                                                                                    Да пожалуйста, смотрите


                                                                                    P.S. И, кстати, что такое «владелец»? В графе, например, или в двусвязном списке, кто чей владелец?

                                                                                    В графе нет владельца, нужно использовать shared_ptr. — Rc<T>, арены и прочее. Пример как можно сделать здесь.


                                                                                    P.P.S.

                                                                                    Пишите на жс, там вообще все разрешено.

                                                                                      –1
                                                                                      Да пожалуйста, смотрите

                                                                                      Да, я посмотрел:

                                                                                      pub(crate) fn alloc_pages(pages: Pages) -> Result<ptr::NonNull<u8>, AllocErr> {
                                                                                          unsafe {
                                                                                              let bytes: Bytes = pages.into();
                                                                                              let addr = libc::mmap(
                                                                                                  ptr::null_mut(),
                                                                                                  bytes.0,
                                                                                                  libc::PROT_WRITE | libc::PROT_READ,
                                                                                                  libc::MAP_ANON | libc::MAP_PRIVATE,
                                                                                                  -1,
                                                                                                  0,
                                                                                              );
                                                                                              if addr == libc::MAP_FAILED {
                                                                                                  Err(AllocErr)
                                                                                              } else {
                                                                                                  ptr::NonNull::new(addr as *mut u8).ok_or(AllocErr)
                                                                                              }
                                                                                          }
                                                                                      }
                                                                                      

                                                                                      Не агритесь вы так, я ничего не имею против Раста жеж. Нравится людям на нем писать — очень хорошо. Просто вот люди, которые на полном серьезе пишут, что «компилятор все за нас проверит», «компилятор гарантирует» — это… ну… Шаг влево — шаг вправо, нестандартная задача, вызов сисколла, сторонняя библиотека без исходного кода (даже и написанная внутри на том же Расте), и все — «гарантии компилятора» превращаются в тыкву сразу. Раздражает не раст, раздражает его неумелая и грубая пропаганда.
                                                                                        0
                                                                                        Если раст завоюет мир (что возможно), то набор паттернов проектирования, подозреваю, изменится настолько, что переживут не все :)))
                                                                                        github.com/rust-unofficial/patterns
                                                                                          0
                                                                                          Там еще столько TODO, что до завоевания мира расту еще далеко :)
                                                                                            0
                                                                                            У меня Redox не открывается дальше начальной страницы, может рокн-рол мертв, а мы еще нет?
                                                                                              0
                                                                                              У меня открывается вроде.
                                                                                                0
                                                                                                Чертова цензура, у меня только через TOR, видимо там внутри сплошной прон…
                                                                                          0

                                                                                          При чем тут пропаганда, если это работает? Да, чтобы реализовать низкоуровневую работу с памятью нужно unsafe, что дальше?


                                                                                          С тем же успехом весь haskell компилируется в машинный код, значит ли это что мы потеряли все что нам давали типы?..


                                                                                          В общем, спор ни о чем.


                                                                                          Programming Defeatism: No technique will remove all bugs, so let's go with what worked in the 70s. ©


                                                                                          Не агритесь вы так

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

                                                                                            +1
                                                                                            Когда мне начинают рассказывать про смирительные рубашки и невероятную свободу, которую он дает, я вспоминаю слова кармака

                                                                                            Ну товарищ, которому он отвечал, тоже в чем-то прав :)
                                                                                            Game dev people discovering Rust is pure comedy. Tweeting out all the benefits, and I'm like «Yup, all the things you mentioned are also available in C++, and you've been ignoring and criticizing them for years». ¯\_(ツ)_/¯
                                                                                              0
                                                                                              Да, чтобы реализовать низкоуровневую работу с памятью нужно unsafe, что дальше?

                                                                                              Нужен не только unsafe, но и libc( в данном случае).
                                                                                              0

                                                                                              А что не так с процитированным вами кодом?

                                                                                                0
                                                                                                Ну он как бы unsafe полностью, все вот эти «компилятор гарантирует» на нем в пролете. А иначе никак.
                                                                                                  0

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


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

                                                                                                    0

                                                                                                    Поэтому есть программы вроде rust belt, которые валидируют unsafe. И иногда находят там ошибки.

                                                                                              –2
                                                                                              Да пожалуйста, смотрите

                                                                                              Проблема подобных ответов заключается в том, что в понятия «аналог» входит то, что является сравнимым хотя-бы по каким-то основным критериям. В данном случае основном критерия аллокатора — работать быстро. Этот аллокатор неконкурентоспособен не то что каким-то лучшим аллокатора, а даже самым банальным.

                                                                                                0
                                                                                                А чего вы минусуете? У вас есть какая-то контр-аргументация? Я что-то неправильно сказал?
                                                                                      +2

                                                                                      Почему нет? Все лайфтаймы и заимствование ссылок описаны в объявлении функции. Далее есть код по одну сторону интерфейса (клиент) и по другую (библитека). Им ничего не нужно знать про друг друга — они работают через интерфейс. Есть время жизни 'static для каких-то синглетонов библиотеке. Safe Раст не возвращает голый указатель. Если мы возвращаем ссылку из функции то должны объявить её время жизни, которое зависит от времени жизни входных параметров. Или мы можем передать владение объектом наверх.


                                                                                      Если мы имеем дело с dll которая на Cи то нужно писать обёртку через unsafe. Ну тут серебрянной пули не существует. Либо жить на си/плюсах либо писать обёртки либо переписывать всё на раст. Очевидно что в зависимтости от ситуации и количества кода то или иное решение оптимально.

                                                              0
                                                              Что-то clang 8 под Windows другое вывел:
                                                              Hello, UB!
                                                              1
                                                              2
                                                              1
                                                              2
                                                                +1

                                                                И? Это ведь УБ, там хоть ханойские башни могут запуститься.

                                                                  0

                                                                  Или майнер биткоинов. :)

                                                                  0

                                                                  На то оно и UB. Попробуйте количество элементов увеличить, или тип контейнера сменить.

                                                                    0

                                                                    Оно ещё и от запуска к запуску может меняться.
                                                                    А может стабильно работать месяцами.
                                                                    Если тестирование налажено хорошо на всех уровнях повезёт, то странность в обработке данных возможно заметить до продакшна.
                                                                    Падение приложения вместо порчи важных данных можно считать большой удачей.

                                                                    0
                                                                    Очень рекомендую проверить свой код на такие случаи.

                                                                    Допустим, вот так: godbolt.org/z/qmzVyN
                                                                  +1
                                                                  Везде и всюду видно обратное

                                                                  Раст целиком и полностью состоит из костылей

                                                                  жава

                                                                  ненужен


                                                                  Судя по качеству аргументов перед вами же типичный лоровец, зачем вы с ним спорите?
                                                                    0

                                                                    С ним давно никто не спорит :)

                                                                  +5

                                                                  Ваш комментарий ниже куда-то делся, но я на него уже подготовил ответ...


                                                                  Целиком и полностью. Зависит от libc, от libc и любых других аллокаторов написаных на си. Использует компилятор и его рантайм написанный на С/С++.

                                                                  libc — это лишь абстракция, где "с" в названии — это лишь история. В Redox OS (ОС на Rust) используется relibc (реализованная по большей части на Rust).


                                                                  В #[no_std] вообще без алокаторов живут (реалии встаиваемых систем). При необходимости можно алокатор свой написать и переопределить, только возникнет резонный вопрос: "а зачем?"


                                                                  Использует компилятор и его рантайм написанный на С/С++.

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


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

                                                                  "Вот когда будет..."


                                                                  Ждите дальше.


                                                                  К тому же, раст состоит целиком и полностью из копирования. Там копируется всё и единственное, что ему позволяет существовать — это llvm и его оптимизации, которые выпиливают все эти копирования.

                                                                  В Rust используется move-семантика по умолчанию. О каком компировании речь вообще?


                                                                  Что, методичка сломалась и ответа нету?

                                                                  Ответа к чему? Вопроса не звучало. Я готов увидеть Ваши патчи в компиляторы перечисленных языков и тогда будем обсуждать по делу. Исходники Rust — это единственные исходники крупного языка программирования, которые не вызывают у меня ужаса, даже более того, компилятор реализован как самый "обычный" проект на Rust и всё логично расположено и код написан с минимальным использованием магии, хорошо документирован и покрыт тестами.


                                                                  Плохо это тем, что очередное пхп украв логику у llvm выдаёт достижения llvm за свои. Без это достижений — это бы пхп было пхп. А оно и было пхп.

                                                                  По Вашей логике выходит, что LLVM справедливо использовать только для компиляторов С++.

                                                                    0
                                                                    Похоже, админы забанили пользователя по чьей-то жалобе. У меня принцип — никого не минусовать, так что жалко его, смешно писал, и кое-что даже по делу было. По мне так форма выражения мыслей неважна — хоть матом, лишь бы Мысль была.
                                                                    PS
                                                                    Самое смешное, что Swift тоже зависит от LLVM :)
                                                                      0
                                                                      Похоже, админы забанили пользователя по чьей-то жалобе.
                                                                      у меня было желание пожаловаться когда он уже окончательно скатился, но я только комментарий написал о том, что при такой подаче искать что-либо в тексте желания не возникает. Но либо сами админы нашли, либо кто-то ещё отписался…
                                                                        0

                                                                        Тьфу ты, только я начал писать ответ на его комментарий недельной давности...

                                                                      0
                                                                      > В Rust используется move-семантика по умолчанию.
                                                                      ========
                                                                      Тут путаница какая-то у меня в голове. Если я создю структуру внутри функции, а потом ее возвращаю вверх по стеку — какие есть варианты кроме копирования? Или в другой тред передаю. Получается, что компилятор сам определяет по ситуации — мув там или копи? Со ссылками то как раз все понятно, непонятно с передачей владения.
                                                                        +3

                                                                        Семантика — это модель, которая предоставляется программисту, в рамках которой он(а) может создавать описывать логику своей программы. Move-семантика — это про то, что после передачи владения значения из переменной А в переменную Б, обращение к переменной А не имеет смысла (в Rust — это ошибка компиляции, а в С++ — поведение не определено [UB]). С точки зрения реализации — это уже вопрос другой. Можно Move-семантику оставить моделью, а асемблер будет производить копии, но чаще всего оптимизационные компиляторы достаточно умны чтобы пользоваться этим преимуществом и избегать копий. Однако, магии не существует и на границах функций (если они не заинлайнятся), данные должны как-то через регистры и стек попасть к вызываемой функции, так что если другого выхода не будет найдено, то данные будут "копироваться".

                                                                          0
                                                                          в С++ — поведение не определено [UB]

                                                                          Это не совсем так. Например, объекты классов из STL после перемещения являются «valid, but unspecified».
                                                                            +1

                                                                            Не знал, спасибо за уточнение. Скажу честно, на С++ мне писать код просто страшно. Я думаю мне всей жизни не хватит чтобы устранить моё невежество в области специфики С++.

                                                                              +2

                                                                              Что означает, что любые операции с ними, кроме вызова деструктора или оператора присваивания — UB.

                                                                                +2

                                                                                Что означает, что любые операции с ними, кроме вызова деструктора или оператора присваивания — Unspecified Behavior.


                                                                                Undefined Behavior тут неоткуда возникнуть.

                                                                                  +2

                                                                                  Мы оба неправы.


                                                                                  Те операции, которые имеют предусловия — UB. Те, которые не имеют — unspecified.

                                                                            0

                                                                            del

                                                                              0
                                                                              Ну, то есть String копируется всегда, хотя по сути это указатель?
                                                                                +1

                                                                                В случае String ничего копироваться не будет, потому что это значение из кучи


                                                                                https://play.rust-lang.org/?version=stable&mode=release&edition=2018&gist=c78abc860e0e096c6f9aaeb909a92181


                                                                                Будет копироваться только сам адрес указателя, который простой int, а все инты как мы знаем проще скопировать. Контент строки остается нетронутым.

                                                                                  0
                                                                                  Например, функция из библиотеки serde_json возвращает мне не String а &str. Я понимаю, что это аллоцировано где-то в куче, и владелец внутри библиотеки сидит. Но мне со ссылками неудобно, и я хочу из этого слайса сделать нормальный String. И вопрос — если я к этому &str применю to_string(), не приведет ли это к новому выделению памяти? По доке получается что приведет, а по жизни?
                                                                                    +6

                                                                                    Очень просто, serde-json ничего не аллоцирует. Функция не может вернуть &str на локальный объект, потому что это была бы висячая ссылка. Отсюда получаем очевидный факт, что все &str которые возвращает функция это просто слайсы, а владелец — строка, переданная в from_str. Зиро кост, аллокаций нет.

                                                                                      +2
                                                                                      То есть библиотека пробрасывает ссылки от входного слайса, полученного в from_slice() — на выход. Это очень круто, поэтому она такая быстрая.
                                                                                        0

                                                                                        В этом и фишка раст.

                                                                                      0

                                                                                      Естественно приведёт. Но вопрос в том, какая именно функция возвращает &str. И нельзя ли эту строку "выковырять" из объекта. И надо ли вообще.

                                                                                        +1
                                                                                        Да, я понял. Выше товарищ ответил, где владелец живет.
                                                                              +1
                                                                              Компилятор Rust написан на Rust

                                                                              фронтенд* компилятора Rust
                                                                                +3

                                                                                Да нет, весь компилятор. Никто не говорит, что таргетом компилятора должен быть машинный код. Таргет csc например это MSIL.

                                                                                  0
                                                                                  Таргет csc например это MSIL.

                                                                                  Даже если бы это и имело практический смысл, в таком случае для запуска программы потребуется CLR, написанный на c/c++.
                                                                                    0

                                                                                    Какая разница? Надеюсь, вы не будете спорить, что csc (C Sharp Compiler) это компилятор?

                                                                                      0
                                                                                      если брать наиболее широкое из возможных определений слова «компилятор», то формально вы правы. Но с такой терминологией препроцессор си тоже можно назвать отдельным компилятором, а clang так вообще целой пачкой. Если же говорить о компиляторе как о программе, преобразующий исходный код в исполняемые файлы, вдруг окажется, что csc — не компилятор.
                                                                                        0

                                                                                        Спор об определениях мне не очень интересен. Майкрософт вряд ли планировал всех запутать или использовать маркетинговый трюк, чтобы все думали, что это компилятор, а на самом деле… Кстати, а что это тогда? Вроде не интерпретатор. А других вариантов и нет. Транспайлер частный случай компиляции, причем тут его правило одноуровневости языков не соблюдается, а на этом перечень исчерпан.

                                                                                          0

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

                                                                                            –1
                                                                                            я бы назвал «исполняемым» «исполняемый процессором» код, а всё остальное — интерпретируемым.
                                                                                              +1

                                                                                              Есть лисп-машины, с тем же успехом можно сделать процессор, выполняющий net код. Что дальше?


                                                                                              clang получается кстати тоже интерпретируемый?

                                                                                                0
                                                                                                вот когда появится такой процессор, тогда я поменяю свое мнение
                                                                                                  0

                                                                                                  Свойство языка не меняется от того, что там где-то какой-то процессор кто-то сделал.


                                                                                                  Кстати да, интерпретатор это штука, которой на вход поступает некий исходный код, а на выходе она его собстенно интерпретирует, выполняя команды. csc ничего не выполняет, он просто кладет некий файлик с IL-кодом. Вопрос, как так?


                                                                                                  И про clang ответьте, пожалуйста. Тоже интерпретатор?

                                                                                                    –1
                                                                                                    Программа имеет смысл только тогда, когда конкретное железо (target) способно её выполнить. И в конвеере от «исходного кода на языке Rust» до выполнения 99% кода написано на с/с++. Вы комфортно обособили написанную на расте часть и обозвали её компилятором. Вот только самостоятельно эта часть не способна обеспечить выполнение кода, а значит, рассматривать её можно лишь как часть (причем очень малую) инфраструктуры.

                                                                                                    И про clang ответьте, пожалуйста. Тоже интерпретатор?

                                                                                                    С чего бы ради то?
                                                                                                      +1
                                                                                                      С чего бы ради то?

                                                                                                      Ну потому что clang делает ровно то же, что и растовый компилятор — собирает llvm из сишного кода.

                                                                                                        –2
                                                                                                        clang'ом обычно называют весь компилятор (набор утилит, обеспечивающих преобразование исходного кода в исполняемые файлы), включая llvm и линкер. Он написан в основном на с/с++. По аналогии, rustc написан… всё еще в основном на с/с++.
                                                                                                          0
                                                                                                          clang'ом обычно называют весь компилятор (набор утилит, обеспечивающих преобразование исходного кода в исполняемые файлы), включая llvm и линкер

                                                                                                          llvm это llvm. Линкер же и в расте есть.


                                                                                                          По аналогии, rustc написан… всё еще в основном на с/с++.

                                                                                                          Раст вообще никогда не был написан на С++. Раст написан на самом расте, и отбутстраплен с OCaml, а никак не с плюсов.

                                                                                                            –1
                                                                                                            llvm это llvm. Линкер же и в расте есть.

                                                                                                            Откуда же в rustc линкер, если у него нет бинарных таргетов? линкера в rustc нет. Линкером там является llvm.

                                                                                                              +2
                                                                                                              Ну, если придираться, то в llvm нет компоновщика. Компоновщик lld — отдельный проект в рамках llvm, как clang или lldb.
                                                                                                              Скомпилированные clang объектные файлы можно скомпоновать в бинарник и ld, и lld, и другими компоновщиками. Rust по умолчанию пользуется lld, но можно компоновать и ld.
                                                                                                                –1
                                                                                                                Компоновщик lld — отдельный проект в рамках llvm, как clang или lldb.


                                                                                                                в рамках llvm
                                                                                                                в llvm нет компоновщика.

                                                                                                                Это явные противоречия. Да и попросту глупость, т.к. все проекты в рамках llvm зависят от llvm и являются его частью.

                                                                                                                Rust по умолчанию пользуется lld, но можно компоновать и ld.

                                                                                                                И что же из этого следует? В rustc появился линкер на rust? Нет.
                                                                                                              –4
                                                                                                              Давайте тогда другой пример. Вот есть у меня исходный код программы на языке rust. Могу ли я запуская только компилятор(ы), написанный(е) на rust, получить из него нативный код процессора? Нет. Можно ли это сделать запуская компилятор(ы), написанный(е) в т.ч. и на с++? Да. Сколько кода такого комплекта написано на rust? Максимум пара процентов. Можно ли считать компилятор, в котором пара процентов кода написана на языке A, написанной только на языке A? Точно нет. Но это противоречит изначальному утверждению:
                                                                                                              Компилятор Rust написан на Rust

                                                                                                              Вывод: изначальное утверждение неверно.
                                                                                                                0

                                                                                                                Хорошо, давайте так. Компилятор раста — компилятор rust кода в байткод LLVM IR. Может ли он его сгенерировать (используя АПИ lLVM или еще как-то)? Может.


                                                                                                                А нативный или нет уже вопрос конкретного процессора. Для ARM ваш x86 плюсовый код не будет нативным, для итаниума тоже не будет. Да и для интела он не совсем нативный, если вспомнить как CISC команды в наше время работают. Вопрос, на какую глубину мы смотрим, вот и все.


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

                                                                                                                  0
                                                                                                                  А нативный или нет уже вопрос конкретного процессора

                                                                                                                  ну так мы обычно отталкиваемся от конкретного процессора (таргета), а потом смотрим, какой код будет для него нативным. И какой бы из существующих процессоров мы ни взяли, ни для одного из них байткод LLVM IR не будет нативным.

                                                                                                                  С другой стороны можно сделать процессор, который нативно выполняет LLVM

                                                                                                                  теоретически можно, практически — это не нужно, ибо сложно и бесполезно. Я всё-таки говорю о чисто практическом аспекте.
                                                                                                                    0

                                                                                                                    Ну а мы все же смотрим больше с точки зрения теории. А с точки зрения теории LLVM от x86 особо не отличается, и компиляторы и в то, и в другое в целом очень похожи, имеют одни и те же модули, и т.п.

                                                                                                                      0
                                                                                                                      Ну а мы все же смотрим больше с точки зрения теории

                                                                                                                      Кто «мы» то? Я вот буквально сообщением выше же написал:
                                                                                                                      Я всё-таки говорю о чисто практическом аспекте.

                                                                                                                      И с самого начала спора я дал недвусмысленно понять, что меня интересует именно практический аспект вопроса:
                                                                                                                      Даже если бы это и имело практический смысл...

                                                                                                                      Да и в других сообщениях мой посыл прослеживался… Почему вы постоянно спорите не читая написанное собеседником?
                                                                                                                        0
                                                                                                                        меня интересует именно практический аспект вопроса

                                                                                                                        С практической точки зрения никто не будет переписывать то, что и так работает, только чтобы победить в интернет споре.

                                                                                                                          0
                                                                                                                          С практической точки зрения никто не будет переписывать то, что и так работает, только чтобы победить в интернет споре.

                                                                                                                          ну я про это и говорю. Использовать по максимуму инфраструктуру LLVM разумно, спору нет. Но вот утверждать что компилятор раста, её использующий, написан только на rust — вот это прям перебор.
                                                                                                        0
                                                                                                        И про clang ответьте, пожалуйста. Тоже интерпретатор?

                                                                                                        Конечно)):


                                                                                                        constexpr int foo() {
                                                                                                            return 2*2;
                                                                                                        }
                                                                                                      –2
                                                                                                      Есть лисп-машины

                                                                                                      Нету. лисп-машина — это интерпретатор лиспа. Причём даже не хардварный. Об этом даже в википедии написано. Зачем люди продолжают повторять эту глупость(что лисп-машины исполняли какой-то лисп)?

                                                                                                      Так же, упускается из виду фундаментальное обстоятельство. Никому и никогда ненужно просто исполнение. Нужно эффективное исполнение. И именно этим лисп-машины и были. Просто хардварные оптимизации характерные для lisp. Такая же история есть с java-байткодом в каких-нибудь arm.

                                                                                                      Все эти ухищрения неэффективны. Именно поэтому они и умерли, а существовали только на начальных этапах. Как в том же arm. Исполнитель откровенно слаб, частота маленькая. Проще туда впихнуть побольше всякой логики и будет быстрее. Но чем дальше — тем хуже.

                                                                                                      Именно поэтому и умер циск. Когда-то это казалось хорошей идеей, а сейчас воспринимается за глупость.

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

                                                                                                        Вам кажется. В качестве контраргумента достаточно посмотреть на засилие электрона вокруг, которму до эффективности как до луны. Однако бизнесу он очень нравитяс. Как же так?

                                                                                                          0
                                                                                                          Вам кажется.

                                                                                                          Нет.
                                                                                                          В качестве контраргумента достаточно посмотреть на засилие электрона вокруг,

                                                                                                          В качестве контр-аргумента подойдёт и rust. Но это не является контр-аргументом, т.к. и одно и второе не является исполнителем и не является хардварным.

                                                                                                          которму до эффективности как до луны.

                                                                                                          Даже если я приму эти попытки, то они в любом случае неудачны. Исполнителем в случае с электроном является хром. Хром является самым эффективным броузером, v8 является самым эффективным исполнителем js.

                                                                                                            0
                                                                                                            Нет.

                                                                                                            Да.


                                                                                                            В качестве контр-аргумента подойдёт и rust. Но это не является контр-аргументом, т.к. и одно и второе не является исполнителем и не является хардварным.

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


                                                                                                            Даже если я приму эти попытки, то они в любом случае неудачны. Исполнителем в случае с электроном является хром. Хром является самым эффективным броузером, v8 является самым эффективным исполнителем js.

                                                                                                            От того что v8 является эффективным софтом на плюсах электрон не стал эффективным. Можно посмотреть на слак который гигабайты отжирает там, где телеграм обходится десятками мегабайт. А то можно дойти до того, что "весь код выполняется на процессоре, вылизанным десятками гениальных инженеров интела, значит весь код эффективный".

                                                                                                              –2
                                                                                                              Ну ок, допустим не является. Дальше что? Какие из этого практические выводы полезные сделать можно?

                                                                                                              Выводы я сделал выше. Я опроверг ваши наивные рассуждения про lisp-машины. Я опроверг ваши рассуждения про «можно сделать какой угодно исполнитель». Нельзя. Этим никто не будет заниматься. Это практический вывод.

                                                                                                              От того что v8 является эффективным софтом на плюсах электрон не стал эффективным.

                                                                                                              Из этого ничего не следует. Разговор был о хардварных исполнителях. Я вам дал возможность подменить тему на софтварные исполнители. В очередной раз подменить тему я вам не дам.

                                                                                                              Можно посмотреть на слак который гигабайты отжирает там, где телеграм обходится десятками мегабайт.

                                                                                                              Какое это имеет отношение к теме? Мы не обсуждали исполняемый код, а обсуждали исполнитель.

                                                                                                              Даже больше скажу. Я утверждал(и именно об этом я говорил), что исполнитель под «неэффективно» нельзя сделать эффективно. Это одно из следствий. И даже непросто «сделать эффективно» просто «сделать» нельзя.

                                                                                                              А то можно дойти до того, что «весь код выполняется на процессоре, вылизанным десятками гениальных инженеров интела, значит весь код эффективный».

                                                                                                              Зачем это написано — я не знаю.

                                                                                                                0
                                                                                                                Выводы я сделал выше. Я опроверг ваши наивные рассуждения про lisp-машины. Я опроверг ваши рассуждения про «можно сделать какой угодно исполнитель». Нельзя. Этим никто не будет заниматься. Это практический вывод.

                                                                                                                Я раст выполняю нативно, очевидный контраргумент.


                                                                                                                Остальное комментировать не буду, а то опять пожалуетесь на другую тему.

                                                                                                                  –3
                                                                                                                  Я раст выполняю нативно, очевидный контраргумент.

                                                                                                                  Нет. Раст не выполняется нативно — нативном выполняется нативный код. Для того и нужен компилятор.

                                                                                                                  Остальное комментировать не буду, а то опять пожалуетесь на другую тему.

                                                                                                                  Там уже нечего комментировать. Ваша аргументация зашла в тупик.
                                                                                                                    0
                                                                                                                    Нет. Раст не выполняется нативно — нативном выполняется нативный код. Для того и нужен компилятор.

                                                                                                                    Ну вот я написал код на расте, получил нативный исполняемый файл. Могу его запустить где угодно? Могу. Так в чем трабл?


                                                                                                                    Там уже нечего комментировать. Ваша аргументация зашла в тупик.

                                                                                                                    Вот я пошел вам на встречу, а вы вот так. Некрасиво, однако )

                                                                                                                      –2
                                                                                                                      Ну вот я написал код на расте, получил нативный исполняемый файл.

                                                                                                                      получил нативный исполняемый файл

                                                                                                                      На этом этапе раста уже нет.

                                                                                                                      Вот я пошел вам на встречу, а вы вот так. Некрасиво, однако )

                                                                                                                      Это я пошел вам на встречу, а мог бы закончить на факапе с lisp-машинами.

                                                                                                                        0
                                                                                                                        На этом этапе раста уже нет.

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


                                                                                                                        Это я пошел вам на встречу, а мог бы закончить на факапе с lisp-машинами.

                                                                                                                        Последний раз я игнорирую ваши наезды.

                                                                                                                          –2
                                                                                                                          Допустим. Какой из этого вывод? Какая польза от этого утверждения? На этом этапе вообще никаких языков нет, ни сипипи, ни хаскеля.

                                                                                                                          Очень простой вывод.

                                                                                                                          Изначальный ваш тезис:
                                                                                                                          Есть лисп-машины, с тем же успехом можно сделать процессор, выполняющий net код. Что дальше?

                                                                                                                          Я, конечно же, опроверг существование лисп-машин(в том виде, в котором декларировали их вы). Опроверг состоятельность попыток реализовать процессор выполняющий lisp/.net и вообще чего угодно. Мир не знает подобных примеров, а все попытки расширять даже архитектуру(привет циск) потерпели неудачу.

                                                                                                                          Я подтвердил это:

                                                                                                                          я бы назвал «исполняемым» «исполняемый процессором» код, а всё остальное — интерпретируемым.

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

                                                                                                                          Последний раз я игнорирую ваши наезды.

                                                                                                                          В чём наезд?

                                                                                                                            0
                                                                                                                            Я, конечно же, опроверг существование лисп-машин(в том виде, в котором декларировали их вы). Опроверг состоятельность попыток реализовать процессор выполняющий lisp/.net и вообще чего угодно. Мир не знает подобных примеров, а все попытки расширять даже архитектуру(привет циск) потерпели неудачу.

                                                                                                                            aJile: http://www.ajile.com/
                                                                                                                            Imsys: http://www.imsystech.com/
                                                                                                                            JOP: http://www.jopdesign.com/index.jsp


                                                                                                                            Вот примеры ЦПУ способных выполнять JVM байткод напрямую, для которых Java — нативный язык. Так что не знаю, что вы там опровергли. Получается Java — нативный язык.

                                                                                                                              –3
                                                                                                                              Опять попытка смерить тему, но неудачная. Про жава-байткод я уже говорил:

                                                                                                                              Просто хардварные оптимизации характерные для lisp. Такая же история есть с java-байткодом в каких-нибудь arm.

                                                                                                                              Так же я там говорил и про причины их появления. Все эти ссылки из википедии — целиком и полностью ложатся на моё описание.

                                                                                                                              По поводу самого «опровержения».
                                                                                                                              JVM байткод напрямую, для которых Java — нативный язык.

                                                                                                                              Это полная чушь. java и jvm-байткод это разные вещи. Далее видна попытка дёргать фразы из контекста, хотя я уточнял:

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

                                                                                                                              jvm-байткод не является java, не является высокоуровневым языком. Так же требует компилятора/транслятора.

                                                                                                                              Так же, такого понятия как java вообще не существует. Существует много версий всяких разных java. И та java, которая используется в embedded — это совершенно другая жава(https://en.wikipedia.org/wiki/Java_Platform,_Micro_Edition).

                                                                                                                              Про эти акселераторы байткода я уже писал. Это существует только на уровне примитивной логики и ничего не умеет. Они не обладают какой-либо производительностью. Они не могут исполнять обычный jvm-байткод.

                                                                                                                              Получается Java — нативный язык.

                                                                                                                              Нет, и это очевидно.

                                                                                                                                0

                                                                                                                                С++ — нативный язык, потому что генерирует x86, исполняемый нативно
                                                                                                                                Java — нативный язык, потому что генерирует JVM, исполняемый нативно.


                                                                                                                                Вы уж либо крестик, либо еще что.

                                                                                                                                  –2
                                                                                                                                  Java — нативный язык, потому что генерирует JVM, исполняемый нативно.

                                                                                                                                  Неверно. Нельзя генерировать jvm, да если имеет ввиду байткод, то байткод никто исполнять не умеет. Я уже говорил, что это embedded java, а не обычная Java. И она целиком и полностью несостоятельна для решения прикладных задач.

                                                                                                                                  С++ — нативный язык, потому что генерирует x86, исполняемый нативно

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

                                                                                                                                  Под нативным в контексте С++ имеется ввиду не то, что он преобразуется в нативный код, а в том что он исполняется нативном на платформе. И противопоставляется это языкам, которые требуют эмуляции платформы. Это называется vm. Именно поэтому то, что исполняется в jvm по определению не может является нативным платформе.

                                                                                                                                  Так же, все эти рассуждения вообще не имеют смысла т.к. никаких хардварных исполнителей байткода не существует. Всё что существует — не является системами/языками общего назначения и вообще находится вне контекста. На этом уже можно закончить.

                                                                                                                                  Ведь я сразу это обозначил. Что на уровне примитивных исполнителей имеет смысл пихать что-то в железо. Но мы, в том числе и я, не обсуждаем тут примитивное/узкоспециализированное железо.
                                                                                                                                    0
                                                                                                                                    Неверно. Нельзя генерировать jvm, да если имеет ввиду байткод, то байткод никто исполнять не умеет.

                                                                                                                                    Вы ссылки выше прочитайте. Вон процессоры, выполняющие байткод.


                                                                                                                                    С++ не может исполняться. Именно об этом говорилось.

                                                                                                                                    А я этого не говорил. Перечитайте фразу "генерирует х86, исполняемый нативно"

                                                                                                                                      –2
                                                                                                                                      Вы ссылки выше прочитайте. Вон процессоры, выполняющие байткод.

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

                                                                                                                                      А я этого не говорил. Перечитайте фразу «генерирует х86, исполняемый нативно»

                                                                                                                                      Ложь.

                                                                                                                                      Есть лисп-машины, с тем же успехом можно сделать процессор, выполняющий net код. Что дальше?

                                                                                                                                      Говорилось именно про высокоуровневые языки и их байткод(хотя причём тут тогда лисп-машины?).

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


                                                                                                                                      Т.е. вы уже сами себя опровергли, т.к. доказали изначальный тезис автора. Что для того, что-бы java-байткод был нативным — должен быть нативный его исполнитель. Очевидно, что вы тут тоже пытаетесь подменить понятия, т.к. javame не является java.

                                                                                                                                      Мой же тезис заключался в том, что 1) нативные реализации байткод/лист-акселераторов существуют. Я это сказал изначально. 2) они ненужны и несостоятельны в общем контексте. Это всё применяется на слабом железе, причём применяется редко и никак вверх не скалируется. Именно поэтому этого никогда за пределами примитивной логики не будет.

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

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

                                                                                                                                      Ничего из этого вы не опровергли. Вы начала мне кидать ссылки из википедии. Абсолютно непонятно зачем, ведь я ещё до вас вам сообщил, что подобные решения есть.

                                                                                                                                        0
                                                                                                                                        Ещё раз, байткод не жава. Зачем я повторю одно и тоже, одно и тоже тому, что попросту всё неудобное игнорирует и повторяет одни и те же фразы, на которые же был дан ответ.

                                                                                                                                        Javac выдает байткод из Java-исходника. Что в этом утверждении вам непонятно?


                                                                                                                                        Ложь.

                                                                                                                                        В каком месте? С++ не генерирут х86? Или х86 это не нативный код?


                                                                                                                                        Говорилось именно про высокоуровневые языки и их байткод(хотя причём тут тогда лисп-машины?).

                                                                                                                                        байткод джавы достаточно высокоуровневый. На одном уровне с LLVM или MSIL.


                                                                                                                                        Т.е. вы уже сами себя опровергли, т.к. доказали изначальный тезис автора. Что для того, что-бы java-байткод был нативным — должен быть нативный его исполнитель. Очевидно, что вы тут тоже пытаетесь подменить понятия, т.к. javame не является java

                                                                                                                                        Я выше скинул процессоры, для которых байткод — нативный формат.

                                                                                                                                          0
                                                                                                                                          Хорошо.
                                                                                                                                          Есть лисп-машины

                                                                                                                                          Покажите мне машину, которая исполняет лисп.
                                                                                                                                            0

                                                                                                                                            Окей, допустим про лисп вы меня уговорили. Нет его, и никогда не существовало, договорились. Но поинт остается. Вон есть джава-машины. Ничем не хуже пример.

                                                                                                                                              –2
                                                                                                                                              Окей, допустим про лисп вы меня уговорили.

                                                                                                                                              Со всем остальным будет тоже самое. Так было с машинами, ir и прочими аллокаторами.

                                                                                                                                              Вот примеры ЦПУ способных выполнять JVM байткод напрямую,

                                                                                                                                              Нет. Но мы пока опустим это. Начнём с вопроса простого:

                                                                                                                                              Такая же история есть с java-байткодом в каких-нибудь arm.

                                                                                                                                              Все эти ухищрения неэффективны. Именно поэтому они и умерли, а существовали только на начальных этапах. Как в том же arm. Исполнитель откровенно слаб, частота маленькая. Проще туда впихнуть побольше всякой логики и будет быстрее. Но чем дальше — тем хуже.


                                                                                                                                              На каком основании вы мне 1) показываете как контр-аргумент моим утверждения то, о чём я заранее и до вас сказал. 2) почему были проигнорированы мои объяснения по этому поводу?

                                                                                                                                              К тому же я не вижу от вас доказательств, что эти накиданные вами ссылки из википедии действительно исполняют jvm-байткод(весь) и целиком и полностью имплементируют jvm хардварно.
                                                                                                                                                0

                                                                                                                                                А в данном вопросе меня не интересует вопрос эффективности, а только вопрос возможности. Ну примерно как факт, что в SystemF возможен фуллинференс. Не очень часто на практике используется, но для теоретических построений очень важный.


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

                                                                                            –4
                                                                                            Никто rustc не декларирует как транслятор из rust в llvm-ir. Мало того, что это попросту глупо. Причин много. Начиная из того, что ir уже llvm, его внутренние представление. И это именно задача фронтенда генерировать промежуточное представление компилятора. Получается, что компилятор компилирует то, что потом компилирует компилятор. Какой смысл вообще разделять фронтенд и компилятор, если и то и компилятор? Заканчивая тем, что на уровне языка множество ссылок на именно генерацию программ. Те же модули существуют именно на бинарном уровне.

                                                                                            Даже если всё это исключить и принять эту логику, то это ничего не изменит. Генератор ir в rustc зависим от llvm. Именно llvm генерирует ir, а фронтенд использует api для генерации ir. Таким образом те части, которая в rustc написаны на rust сами генерировать ir не могут.

                                                                                            Единственная соломинка здесь — это mir. Но это тоже тупиковый путь. Это некая форма rust. Её ничто не умеет исполнять. Она декларируется как промежуточное представление. Это не таргет. Если это таргет, то зачем компилятору что-то делать с таргетом и куда-то его преобразовывать(пусть и внешней логикой)?

                                                                                              0
                                                                                              Единственная соломинка здесь — это mir. Но это тоже тупиковый путь. Это некая форма rust. Её ничто не умеет исполнять. Она декларируется как промежуточное представление. Это не таргет. Если это таргет, то зачем компилятору что-то делать с таргетом и куда-то его преобразовывать(пусть и внешней логикой)?

                                                                                              Если бы вы почитали, зачем MIR вообще придумали, то увидели бы, что это сделано для более простых и глобальных оптимизаций и некоторых других вещей. Что насчет "внутренних представлений", то етсь такая штука, как абстракция, и они как матрешки нанизываюстя друг на друга. Есть HAL, который абстрагирует ОС, которую абстрагирует clib, которую абстрагирует фреймворк, который абстрагирует...

                                                                                                –2
                                                                                                Если бы вы почитали, зачем MIR вообще придумали, то увидели бы, что это сделано для более простых и глобальных оптимизаций и некоторых других вещей.

                                                                                                Пруфы. К тому же, что вообще из этого следует? Я опроверг ваши рассуждения. Абсолютно неважно то, чем является mir. Таргетом в rustc может является только он, ведь только его генерирует rustc сам.

                                                                                                Что насчет «внутренних представлений», то етсь такая штука, как абстракция, и они как матрешки нанизываюстя друг на друга.

                                                                                                Это набор слов. Узнайте значение понятия «таргет». Внутреннее представление, либо промежуточное представление — это по определению то, что находится до таргета. Если бы оно было таргетом — оно бы не называлось промежуточным/внутренним.

                                                                                                Есть HAL, который абстрагирует ОС, которую абстрагирует clib, которую абстрагирует фреймворк, который абстрагирует...

                                                                                                И? Я вас где-то спрашивал про «что такое промежуточное представление»? Я вас где-то спрашивал про «что такое абстракции»? Нет и нет. Зачем вы мне это пишите?

                                                                                                Вы пытались сказать, что в rustc rust-код генерирует ir. Это неправда. Вам нужно на это отвечать.
                                                                                                  0

                                                                                                  rustc генерирует LLVM IR, который является IR. В процессе этой генерации он внутри себя проходит через промежуточное представление MIR.


                                                                                                  И да, хамить в комментах последнее дело.

                                                                                                    –4
                                                                                                    rustc генерирует LLVM IR

                                                                                                    Нет. Контекст был «на rust». rustc не генерирует ir — его генерирует llvm.

                                                                                                    В процессе этой генерации он внутри себя проходит через промежуточное представление MIR.

                                                                                                    Я уже это говорил. mir — это единственное, что генерирует rustc сам. Вы утверждали, что rustc является компилятором(транслятором) во что-то там. Вы не уточняли во что именно он транслируется(понятно что в ir).

                                                                                                    И вот, когда вы знаете, что rustc(сам) генерирует только mir. Таким образом отсюда:

                                                                                                    Да нет, весь компилятор. Никто не говорит, что таргетом компилятора должен быть машинный код.

                                                                                                    Может следовать только «таргет == mir». Почему mir не может являться и таргетом и промежуточным представлениям понятно.

                                                                                                    Таким образом я доказал, что ваше утверждение некорректно и не имеет смысла.

                                                                                                    И да, хамить в комментах последнее дело.

                                                                                                    Конкретика. Где «хамить» и в чём «хамить» заключается.

                                                                                                      0
                                                                                                      Нет. Контекст был «на rust». rustc не генерирует ir — его генерирует llvm.

                                                                                                      А что он тогда генерирует?


                                                                                                      Я уже это говорил. mir — это единственное, что генерирует rustc сам. Вы утверждали, что rustc является компилятором(транслятором) во что-то там. Вы не уточняли во что именно он транслируется(понятно что в ir).

                                                                                                      То есть LLVM понимает MIR, раз уж раст после него ничего не генерирует? Вот так новость.

                                                                                                        –2
                                                                                                        А что он тогда генерирует?

                                                                                                        Только mir.

                                                                                                        То есть LLVM понимает MIR, раз уж раст после него ничего не генерирует? Вот так новость.

                                                                                                        Эту глупость, а не новость. Я уже всё объяснял. llvm предоставляет api для генерации ir. Если мы берём те части, которые в rustc написаны на rust(а именно об этом шла речь), то они никак не генерируют ir. Они используют хайлевел llvm-api через биндинги.

                                                                                                        Повторю ещё раз. Те части, которые в rustc написаны на rust могут генерировать ТОЛЬКО mir. Из этого факта никак не следует, что llvm должен начать понимать mir.
                                                                                                          0

                                                                                                          А как из MIR получается исполняемый x86 файл? LLVM не понимает MIR, сам раст из MIR ничего не генерирует. ПО идее мы должны были бы застрять на этапе MIR.


                                                                                                          image


                                                                                                          Вот кто конкретно этот LLVM IR генерирует?

                                                                                                            –2
                                                                                                            Вот кто конкретно этот LLVM IR генерирует?

                                                                                                            llvm. Я уже отвечал на это. llvm-ir генерирует llvm-логика, которая написана не на расте. Далее эту внешнюю логику раст использует через биндинги. Так работает любой llvm-фронтенд.

                                                                                                            Эти рассуждения вообще не имеют смысла, ведь rustc попросту слинкован с llvm и без него в принципе существовать не может. Ваше утверждение изначально ложно. Но я пошел вам навстречу и говорю о том, что может(гипотетически) rustc в отрыве от llvm. Может он только генерировать mir(возможно ещё какие-то подобные промежуточные представления).

                                                                                                            Компилятор Rust написан на Rust

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

                                                                                                            Я думаю вы знаете, что из одного языка можно вызвать логику на другом языке. Именно таким механизмом пользуется rust.
                                                                                                              0
                                                                                                              llvm. Я уже отвечал на это. llvm-ir генерирует llvm-логика, которая написана не на расте. Далее эту внешнюю логику раст использует через биндинги. Так работает любой llvm-фронтенд.

                                                                                                              Давайте я вам скину MIR, а вы с помощью LLVM попробуете из него получить LLVM IR? Спойлер, у вас не выйдет, потому что это просто не так.

                                                                                                                0
                                                                                                                Давайте я вам скину MIR, а вы с помощью LLVM попробуете из него получить LLVM IR? Спойлер, у вас не выйдет, потому что это просто не так.

                                                                                                                Давайте мы поступим проще. Вы берёте rustc без llvm и генерируете ir. Если ваши рассуждения верны — вы сможете это сделать, ведь вы утверждали, что «rustc САМ(т.е. средствами кода написанного на rust) генерирует что-то там(как я понял — это IR)». Если сам — сгенерируйте.

                                                                                                                К тому же, зачем вы продолжаете повторять глупости про mir и игнорируете все мои контр-аргументы? Из того, что llvm не умеет mir не следует, что rustc умеет генерировать(сам) ir. Это очевидно.
                                                                                                                  –1

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


                                                                                                                  Еще раз, раст это преобразователь Rust -> LLVM IR. LLVM дальше компилирует LLVM IR в таргет код платформы. Естественно именно задача раста сгенерировать вход для LLVM, коим является LLVM IR. В этом и смысл всей технологии. Тем же самым занимается clang, который тоже является компилятором. И не потому, что он компилирует си.

                                                                                                                    0
                                                                                                                    Ну вон, пожалуйста, безо всякого LLVM сгенерил его.

                                                                                                                    Покажите. Где? То, что вы там линкуете — генерирует rustc, который слинкован с llvm. Вам нужно убрать оттуда llvm и сгенерировать ir.

                                                                                                                    Еще раз, раст это преобразователь Rust -> LLVM IR.

                                                                                                                    Нет. Это глупость.

                                                                                                                    Естественно именно задача раста сгенерировать вход для LLVM, коим является LLVM IR.

                                                                                                                    Неверно. Никакой раст никакой ir не генерирует. раст занимается вызовов llvm-api, который генерирует ir. Именно llvm генерирует ir.

                                                                                                                    Я вам советую изучить тему перед тем как что-то утверждать. Начините отсюда github.com/rust-lang/rust/tree/master/src/rustllvm Далее github.com/rust-lang/rust/tree/master/src/librustc_codegen_llvm который напрямую забинден с rustllvm.

                                                                                                                    В этом и смысл всей технологии.

                                                                                                                    Нет, вы не изучали вопрос. Изучите.

                                                                                                                    IR является платформо-зависимым во многих аспектах. Он достаточно сложен. Именно поэтому никакой фронт его не генерирует.

                                                                                                                    llvm предоставляет api, который и занимается генерацией ir. Именно этот api использует rustc и любой другой фронт. Я даже больше скажу. Сам llvm знает про раст. Без поддержки llvm никакой фронт существовать не может.

                                                                                                                    Тем же самым занимается clang, который тоже является компилятором. И не потому, что он компилирует си.

                                                                                                                    Зачем вы ссылаетесь на clang? К чему это? Вы утверждали, что код на rust сам генерирует ir. Это неправда. В ситуации с clang это не работает. Да, тут так же ir генерирует llvm, но llvm написан на С++, а значит С++ генерирует для себя ir. И неважно где этот код лежит.

                                                                                                                    К тому же, clang это неотъемлемая часть llvm. rustc же внешняя часть.
                                                                                                                      –1
                                                                                                                      Зачем вы ссылаетесь на clang? К чему это? Вы утверждали, что код на rust сам генерирует ir. Это неправда. В ситуации с clang это не работает. Да, тут так же ir генерирует llvm, но llvm написан на С++, а значит С++ генерирует для себя ir. И неважно где этот код лежит.

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