В Rust действительно на какой-то стадии (честно, последний год не следил) есть концепция Tree Borrows. Но она ведь требует runtime поддержки и не является фундаментальным решеним для статических компиляторов. Мне вот покоя не давал этот пример
let mut root1 = 42;
let mut root2 = 43;
let mut ptr = &mut root1 as *mut i32;
let (x, mut y) = unsafe { (&mut *ptr, &mut *ptr) };
*x = 13;
ptr = &mut root2 as *mut i32;
y = unsafe {&mut *ptr };
*y = 20;
let val = *x + *y;
Я не являюсь экспертом языка rust, но насколько я понял, его разработчки попытались взять лучшее из подходов Fortran и C/C++, приправить safe/unsafe философией, где нужно, и в целом получили интересное решение. Является ли оно лучшим? Я думаю, что нет.
Давайте немного улучшим ваш пример, заменив assert на что-то более специфичное (когда мы хотим оптимизаций, мы assert'ы, как правило, выключаем). Для clang есть соответствующие builtin'ы:
int f(int x, int y) {
__builtin_assume(x != y);
*x = 42;
*y = 14;
return *x;
}
Внезапно, это ничего не даёт: ассемблер получится с всё тем же лишним релоадом. Связано это с особенностями работы alias analysis. Тем не менее, есть более тонкая настройка:
int f(int x, int y) {
__builtin_assume_separate_storage(x, y);
*x = 42;
*y = 14;
return *x;
}
Тем не менее, стандартизация подобных вещей как раз-таки приводит нас к контрактному программированию и тому, о чём я рассказал, когда рассказывал disjoint
В Rust действительно на какой-то стадии (честно, последний год не следил) есть концепция Tree Borrows. Но она ведь требует runtime поддержки и не является фундаментальным решеним для статических компиляторов. Мне вот покоя не давал этот пример
Я не являюсь экспертом языка rust, но насколько я понял, его разработчки попытались взять лучшее из подходов Fortran и C/C++, приправить safe/unsafe философией, где нужно, и в целом получили интересное решение. Является ли оно лучшим? Я думаю, что нет.
Тут надо аккуратнее говорить, т.к здесь UB -- unspecified, не undefined. А так да, с этим есть определённого рода сложности
Давайте немного улучшим ваш пример, заменив assert на что-то более специфичное (когда мы хотим оптимизаций, мы assert'ы, как правило, выключаем). Для clang есть соответствующие builtin'ы:
Внезапно, это ничего не даёт: ассемблер получится с всё тем же лишним релоадом. Связано это с особенностями работы alias analysis. Тем не менее, есть более тонкая настройка:
И вот тут как раз-таки у компилятора развязываются руки
Тем не менее, стандартизация подобных вещей как раз-таки приводит нас к контрактному программированию и тому, о чём я рассказал, когда рассказывал
disjoint