Borrow checker проверяет и данные в куче, его правила работают и в многопоточном коде
В Rust локальные переменные могут выделяться в куче, как это происходит в скриптовухе во многих языках с динамическими типами данных. Однако, фундаментальный принцип работы borrow checker-а — каждая область памяти может в одно время изменяться только одним фрагментом кода. То есть, по сути данные являются локальными для некоторых функций. Или же данные общие, но изменять их нельзя.
Так еще делает, если я не ошибась, Ponylang — скорее всего по стопам раста.
С каких пор толпа фанатиков - проблема языка? У твоего любимого тоже есть своя толпа фанатиков, если он конечно не эталонное ненужно. Теперь твой любимый язык проблемный?
время компиляции
Ух блин, я то думал, что рантайм имеет решающее значение, а оказывается компиляция. :( Срочно жду бенчмарки, где компилируемые языки сравнивают по времени компиляции
Тебе самому хоть раз приходилось писать достаточно большой проект, на котором время компиляции раста было бы пролемой? Мне нет. Так-то и я могу привести в пример хромимум(если он еще жив), который на плюсах написан и собирается несколько часов
Вот. В точку. Какой язык лучше раста? Альтернатив нет. Какой язык лучше Java? Альтернатив все равно нет. И да, я завидую. Потому что могу сделать язык лучше, но он никому не нужен — индустрия будет еще минимум 5-10 лет сидеть на C++/Java/C#, даже если мой язык окажется божественным и неповторимым. Блин, даже Rust можно было сделать лучше, но в какой-то момент его отдали на растерзание эффективным менеджерам, у которых почти получилось похоронить язык.
У любого компилируемого языка есть время компиляции. Почему ты думаешь, что у раста оно неприемлемое?
Rust компилирует сам себя почти час. При том, что это порядка 400 тыс строк кода — детский сад. Посмотри на GCC, в котором 15 млн строк. Сколько будет самокомплиироваться Rust, когда дорастет до таких объемов? Круглые сутки?
Лучше для того, чтобы реализовать на нем средний по больнице коммерческий проект. То есть, с ограничением на время реализации и вообще затрачиваемые на реализацию ресурсы, при некоторой гарантии работоспособности. Он Легионер прав, потому что ЯП выбирают манагеры, а не программисты — а манагеры выбрали Java, C++, и Rust.
Растовчане советуют не компилировать код лишний раз. А использовать
Это всё попытки как-то спасти проект, который уперся в глухую стенку и дальше не двигается. Там вон для C++ придумывают резидентные сервера сборки, но в итоге переходят на модули, потому что без изменения архитектуры языка дальше развивать сборку некуда. У раста та же ситуация — спроектирован язык плохо, и всё проведенное растом в яслях время было упущено, вовремя задержка развития не обнаружена (PS: а я подчеркиваю, что еще в самом начале развития у раста была явная проблема со временем компиляции, на которые упорно не обращали внимание). И теперь у нас ребенок-аутист, который не может говорить, читать, писать, избегает взгляда глаза в глаза, но зато может раскладывать предметы по порядку.
Ты скажешь конкретно что там плохо? Когда компилятор где-то компилируется час, это не проблема. Именно в каком месте плох язык, так что в яслях можно было исправить?
Хоть мне и блевать охота от сего тула, но все таки Си диез действительно одно из самых используемых... Типо я реалист
Элементарно, Ватсон: до восьмерки Java была адом, при этом из альтернатив было только C#. Конечно, потом подъехал уже и Go, и сами разрабы Java оживились, потому что язык рисковал остаться вообще без коммерческих ниш и отправиться на помойку. Это волшебные механизмы «рыночка», которые я долго не мог понять: почему вся экономика может тратить сотни миллиардов долларов для обхода проблем, которые можно было бы решить один раз за 100 млн долларов?
Ты скажешь конкретно что там плохо? Когда компилятор где-то компилируется час, это не проблема. Именно в каком месте плох язык, так что в яслях можно было исправить?
Я линк давал на обзор этой проблемы с конкретными причинами:
Лучше уже не будет. Проблема в том, что часами компилируется не только компилятор, но еще и любой другой проект на расте такого же или большего размера. А что такое 400 тыс строк? Это проект на десять рыл за пару лет работы. У меня команда из 7 человек где-то за 8 лет написала миллион — и это скромненькая такая разработка для полупубличного пользования, даже не какой-то крупный высокобюджетный проект.
Soundness holes. Если уж начинать сраться про безопасность - то отсюда, но поехавшие хейтерки обычно не знают Rust чуть более чем совсем, поэтому аргументация скатывается в какое-то УГ.
Куча нужных и ожидаемых фич (GAT, полная версия const generics, trait bounds на самих trait-ах, etc.), которые зависли в ожидании chalkification.
Какая разница, является ли локальная переменная данными прямо в стэке или ссылкой в стэке на данные в куче? В обоих случаях переменная локальная, поскольку не может быть прочитана или изменена из другой функции.
Почему не может? Что тебе мешает её вернуть из функции и передать в другую?
Что мешает мне целочисленную переменную вернуть из функции? Да ничего. Однако, это не отменяет того факта, что эта переменная была локальная для этой функции во время выполнения этой функции.
Я все-таки ожидал, что ты в качестве примера приведешь передачу ссылки в вызываемую функцию, а не возврат в вызывающие, что есть более сложным случаем, поскольку как бы вызывающая функция у нас не закончилась, но и управление ведь из нее ушло за пределы видимости локальных переменных, а локальные переменные другие функции, тем не менее видят. Оба варианта передачи локальных данных есть в том же Си, и это не отменяет того факта, что они локальны и попытка выполнить небезопасную операцию за пределами видимости приведет к UB в сишке или же к ошибке компиляции в Rust без unsafe.
Или расшарить что-то в куче между потоками. Опять же, вектор всего один.
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
fn callee1(a: Arc<Mutex<Vec<i32>>>) {
let mut a = a.lock().unwrap();
a.push(6);
a.push(7);
}
fn callee2(mut a: Arc<Mutex<Vec<i32>>>) {
let mut a = a.lock().unwrap();
a.push(8);
a.push(9);
}
fn caller() {
let mut a = Arc::new(Mutex::new(vec![1, 2, 3, 4, 5]));
let thread1 = thread::spawn({
let a = a.clone();
move || callee1(a)
});
let thread2 = thread::spawn({
let a = a.clone();
move || callee2(a)
});
thread1.join();
thread2.join();
let a = a.lock().unwrap();
for i in a.iter() {
print!("{} ", i);
}
println!();
}