The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



"Выпуск языка программирования Rust 1.77"
Версия для распечатки Пред. тема | След. тема
Форум Разговоры, обсуждение новостей
Исходное сообщение [ Отслеживать ]
Подсказка: Для слежения за появлением новых сообщений в нити, нажмите "Проследить за развитием треда".
. "Выпуск языка программирования Rust 1.77" +1 +/
Сообщение от n00by (ok), 27-Мрт-24, 18:32 
>> Исходный вопрос, как я понял, сугубо практический. Вроде "я так всегда делал, адрес не брал, и оно в коде ведёт себя как enum".
> Ну, как бы это сказать. Мне приходилось брать адрес от литерала, например,
> ты можешь попробовать сделать:
>     foo(&5);
> Я не знаю как там C или C++ с этим обходится, rust
> легко создаст 5 в памяти, и передаст в функцию её адрес.
> Вот с константой примерно то же самое.

В таком виде с типом int не сработает, адрес можно брать у lvalue, но не у rvalue.

Потому приходится городить неявное создание объекта (экземпляра типа):

#include <iostream>

const int& wrap(const int& i) { return i; }

int main() {
  // ошибка: операнд унарной операции «&» должен быть lvalue-выражением
  // std::cout << "адрес копии: " << &5 << std::endl;
  std::cout << "адрес копии: " << &wrap(5) << std::endl;
  std::cout << "адрес: " << &"&wrap(5)" << std::endl;
}

С "литералом" срабатывает, поскольку это массив char-ов. Он со времён Си где-то должен быть размещён, значит это объект и адрес у него есть. Такая и многие другие странности происходят из обратной совместимости с Си.

>> Если передать my_constant параметром в функцию, то адрес у аргумента получить можно, но это окажется неявно созданная копия.
> Try it. Я забавы ради попробовал в rust'е, он мне даёт два
> одинаковых адреса для &5u32 и &MY_CONSTANT, который был объявлен как const
> MY_CONSTANT: u32 = 5;

const int& wrap(const int& i) { return i; }

int main()
{
  {
    std::cout << "адрес копии: " << &wrap(5) << std::endl;
  }
  {
    std::cout << "адрес другой копии: " << &wrap(6) << std::endl;
  }
}

$ g++ vol2.cpp -o vol2 && ./vol2
адрес копии: 0x7fff60eb50a4
адрес другой копии: 0x7fff60eb50a4

Здесь одинаковые адреса объясняются очень просто - время жизни первого объекта закончилось и используется тот же адрес в стеке для второго. Но это так случайно совпало.

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

> C/C++ может быть будет создавать копию, потому что ему надо гарантировать неизменность
> MY_CONSTANT, но если он даст адрес туда... Хотя &5 наверное будет
> ведь const int*, да? Он не позволит ничего менять, и тогда
> вроде нет нужды создавать копию. Хз, короче, раст полагается на то,
> что если есть *const u32, то это реально const, что он
> не позволит программисту поменять значение, а если программист окажется настойчивым и
> изобретательным и поменяет, то он ССЗБ.

В примере выше const int*. Вернуть можно и не константу (через const_cast), но без const у аргумента функции ссылка не свяжется с 5. "Копия" тут в том смысле, что rvalue и lvalue исторически получились из выражения копирования значения (справа) в объект (слева) при инициализации.

int lvalue = 5; // rvalue

В случае 5 оно хранится как операнд машинной инструкции, и его адрес получить можно не на всяком процессоре.

Вот эта императивность и определяет многое в языке. Rust в основе функциональный, это почему-то тщательно скрывают, но лично для меня многое объясняет. let lvalue = 5 оказывается чистой функцией, а не объектом в памяти, который по семантике надо сохранить, после чего оптимизировать.

>> Если видимость единицей трансляции не ограничена, то это внешнее связывание, но extern не написано же.
> Может мне память изменяет... Насколько я помню идею за extern, то она
> говорит компилятору, что ему следует верить, что переменная будет определена где-то
> в другом месте, а здесь только декларация. А если не указано
> слово static, то имя экспортируется по-дефолту, и компилятор ничего не может
> предполагать о том, будет ли нужен адрес этой переменной или нет.
> Так? Меня память не подводит?

Это в Си так (но и определения можно делать с extern, не только объявления). В Си++ по умолчанию для констант внутреннее связывание, если определены в неймспейсах. При этом вообще всё очень желательно писать в неймспейсах. Если меня память не подводит.

>> Логика Rust довольно простая. Автор посмотрел на OCaml и его осенила гениальная мысль - почему бы в Си++ не сделать всё const по умолчанию, ведь это разом решит множество проблем (в частности избавит от всяких фокусов вроде возврата ссылки на локальную статическую переменную, что бы скрыть связывание). Но позже почему-то ушёл из проекта.
> Неее... Это сильное переупрощение, и я бы даже сказал, что просто неверно.
> У него не было идеи делать свой C++ с блекджеком и
> шлюхами, раст начал конвергировать к C++ позже, когда понабежало всяких других
> разработчиков, и те начали соревноваться с C++ в плане скорости генерируемых
> программ. Вот тут можно почитать, что он задумывал, и как его
> идеи расходились с идеями других: https://graydon2.dreamwidth.org/307291.html Может
> быть это даже ответ на вопрос, почему он ушёл из проекта,
> или по-крайней мере часть ответа.

Это банально мои проекции, и по случайному совпадению они помогли мне понять код на Rust. C++ с константностью по умолчанию оказался бы принципиально другим языком нежели исходный, более функциональным, чем императивным. И ни в коем случае не претендовал бы на замену. Вообще, появление активных людей, кто начинает повсюду бегать с криками "вот этим можно заменить вон то", как бы и не должно ставиться целью, поскольку закономерно вызовет ответную реакцию.

По ссылке автор пишет больше о деталях реализации, а их, понятное дело, множество вариантов. Например, я не додумался до сборщика мусора (религия запрещала), потому дальше идей дело не пошло.

>> Оно в принципе будет работать и с extern const int x, если определить ссылку на константу через const_cast, но придётся менять защиту страницы памяти константной секции ELF-а, что бы не упало при попытке записи.
> Йее, я вижу начало доходить потихоньку? Значение переменной, даже константной это значение
> переменной, её можно поменять, пускай для этого и придётся прибегать ко
> всяким трюкам, иногда системно-зависимым. Но попробуй в рантайме поменять значение из
> enum'а.

Потому что enum это значение (rvalue), а "константная переменная" (пусть простит меня учительница русского) - объект (lvalue), хранящий значение. Это наследие Си, а в плюсах очень старались убрать объекты из секции данных, потому изменили связывание для констант. Сейчас разрешили enum-ы с отличными от int типами членов, а как поступали раньше, когда нужна константа с sizeof == 1? Определять её как const uint8_t. Это могли прописать в правилах кодирования. :)

>> Так в том примере две разные переменные с одним именем.
> Да, это т.н. shadowing, одна переменная затеняет другую. Но константу не удастся
> затенить, раст будет плевать тебе в лицо и обвинять в безрукости
> при попытке такого.

Вот это существенное отличие.

Ответить | Правка | Наверх | Cообщить модератору

Оглавление
Выпуск языка программирования Rust 1.77, opennews, 22-Мрт-24, 14:05  [смотреть все]
Форумы | Темы | Пред. тема | След. тема



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру