The OpenNET Project / Index page

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



Вариант для распечатки  
Пред. тема | След. тема 
Форум Разговоры, обсуждение новостей
Режим отображения отдельной подветви беседы [ Отслеживать ]

Оглавление

Выпуск языка программирования Rust 1.77, opennews (?), 22-Мрт-24, (0) [смотреть все]

Сообщения [Сортировка по времени | RSS]


177. "Выпуск языка программирования Rust 1.77"  +1 +/
Сообщение от Аноним (-), 23-Мрт-24, 15:12 
Потому что const требует обязательного указания типа. Логику этого я не совсем понимаю, но думаю что есть причины.

Но ты можешь написать:

    let hello = c"Hello, world!";

Судя по описанию фичи это должно сработать. Но это будет не константа, а immutable переменная. Константу компилятор может заменять значением, как ему хочется, всякие там constexpr считать из неё, а вот immutable переменная -- это всё же переменная, хоть она и неизменная.

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

195. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от Аноним (-), 23-Мрт-24, 17:31 
А чем отличается немутабельная переменная let a, от константы - const? Ведь и ту, и другую сущность нельзя изменять.
Ответить | Правка | Наверх | Cообщить модератору

196. "Выпуск языка программирования Rust 1.77"  +1 +/
Сообщение от Аноним (184), 23-Мрт-24, 18:16 
> А чем отличается немутабельная переменная let a, от константы - const? Ведь
> и ту, и другую сущность нельзя изменять.

простите, а вы точно цппшник? как _не_растоман спрашиваю.

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

226. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от n00by (ok), 25-Мрт-24, 12:18 
>> А чем отличается немутабельная переменная let a, от константы - const? Ведь
>> и ту, и другую сущность нельзя изменять.
> простите, а вы точно цппшник? как _не_растоман спрашиваю.

Так он и спрашивает, чем отличаются. Немутабельная переменная в "цпп" это что? const и extern linkage? Оно не нужно здесь.

Или вместо указателя на секцию данных получится аллокация всего массива на стеке

{
  const char hello[] = {"Hello, world!"};
}

?

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

232. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от Аноним (-), 25-Мрт-24, 17:11 
> Так он и спрашивает, чем отличаются.

Когда я упоминал выше разницу между immutable variable и constant я, кажется, всё сказал, не? Я думал он перебирает с троллингом, прикидываясь настолько тупым, каких не бывает. Но если это не троллинг, я могу объяснить разницу в терминах C/C++.

Сравни:

    const int my_constant = 5;

и

    enum {
        my_constant = 5;
    };

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

> Или вместо указателя на секцию данных получится аллокация всего массива на стеке

Никто не знает. Если это константа, то это всё на усмотрение компилятора, который будет смотреть как эта константа используется, и принимать решение. Может ты из этого массива используешь только третий байт, так зачем вообще в такой ситуации тратить место под массив, почему бы не подставить непосредственно в код значение третьего байта?

> аллокация всего массива на стеке
> {
>   const char hello[] = {"Hello, world!"};
> }

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

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

245. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от n00by (ok), 26-Мрт-24, 11:46 
>> Так он и спрашивает, чем отличаются.
> Когда я упоминал выше разницу между immutable variable и constant я, кажется,
> всё сказал, не?

Скорее, я не достаточно подробно написал, что такое external linkage и не упомянул про storage duration.

> Я думал он перебирает с троллингом, прикидываясь настолько
> тупым, каких не бывает. Но если это не троллинг, я могу
> объяснить разницу в терминах C/C++.
> Сравни:
>     const int my_constant = 5;
> и
>     enum {
>         my_constant = 5;
>     };

Если речь именно о плюсах, а не Си, то нет существенной в данном контексте (особенно, когда нет static и область видимости не очевидна) разницы. И то и то не занимает места в секции данных, будет подставлено непосредственным операндом в машинную инструкцию. Соответственно этому стандарт плюсов и позволяет использовать первое вместо второго (распространённая практика определять 8-ми разрядные константы как const uint8_t, пока enum мог быть только типа int).

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

Это в случае переменных со связыванием. Отсюда при отсутствии static и возникает вопрос, а не определяется ли константа вот так:

void f()
{
  const int my_constant = 5;
}

>> Или вместо указателя на секцию данных получится аллокация всего массива на стеке
> Никто не знает. Если это константа, то это всё на усмотрение компилятора,
> который будет смотреть как эта константа используется, и принимать решение. Может
> ты из этого массива используешь только третий байт, так зачем вообще
> в такой ситуации тратить место под массив, почему бы не подставить
> непосредственно в код значение третьего байта?

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

>> аллокация всего массива на стеке
>> {
>>   const char hello[] = {"Hello, world!"};
>> }
> Сишное мышление детектед.

В Си ничего нет про аллокацию на стеке. Там это называется automatic storage duration, и всякий сишник знает, что стека может вообще не быть.

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

Ну как кто? Вон выше было "первое же -- это имя, с которым линкеру придётся разбираться". Вот это static storage duration, оно же выделение на этапе трансляции, если на рабоче-крестьянском языке.

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

249. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от Аноним (-), 26-Мрт-24, 14:41 
> Если речь именно о плюсах, а не Си, то нет существенной в данном контексте (особенно, когда нет static и область видимости не очевидна) разницы. И то и то не занимает места в секции данных, будет подставлено непосредственным операндом в машинную инструкцию.

Не совсем. const int my_constant может быть операндом операции взятия адреса, и все такие операции должны возвращать одинаковый адрес. В случае же с enum { my_constant = 5}, каждое взятие адреса &my_constant может возвращать свой собственный адрес. Технически правда, я думаю они всё равно все будут одинаковыми, но это не гарантия компилятора, это способ имплементации компилятора.

> Это в случае переменных со связыванием. Отсюда при отсутствии static и возникает вопрос, а не определяется ли константа вот так

Тут компилятор тоже должен предоставить константе валидный адрес, другое дело, что если оптимизатор достаточно умён, и видя что время жизни ограничено лексическим скоупом, он может подметить ситуацию, когда адрес не используется. Такие штуки становятся сложнее, если константная переменная доступна для юнита (топ-левел декларация static const int), потому что то в чём компиль реально силён, и ещё сложнее, если она не ограничена юнитом (там только LTO может помочь, теоретически, а практически я не знаю, помогает ли он).

> В Си ничего нет про аллокацию на стеке. Там это называется automatic storage duration, и всякий сишник знает, что стека может вообще не быть.

Сишное мышление проявляется не в использовании слова "стек", а в озабоченности стораджем в ущерб всему остальному. C не проводит чётко разницы между, например, переменной, сторейжем ассоциированным с ней, и значением сохранённым в этом сторейже. Лол, из-за этого, я когда столкнулся с растом впервые, недели две бился головой о клавиатуру, не мог понять логики. Сторейж переменной может меняться по ходу дела, компилятор не даёт гарантий на этот счёт, значение в строейже может меняться, или сторейж может уходить от одной переменной к другой (например когда ты делаешь move: let my_big_value = ...; foo(my_big_value); функция foo будет работать с тем же самым куском сторейжа, который был ассоциирован с my_big_value, но переменная в ней будет другая).

В расте const декларация -- это имя для _значения_, let декларация -- это имя для переменной, которая может хранить значение, а может и не хранить. let делает _переменную_ неизменной, но нет гарантий что в сторейж никто не будет писать. В том примере выше, когда мы my_big_value отправляем в функцию, она может начать менять это значение. А вот константа... ты не можешь у неё отнять сторейж, ты не можешь изменить значение хранящееся в нём. Ты не можешь "затенить" константу другой декларацией, чтобы создать лексическую изменяемость:

const int x = 5;
{
    const int x = 6;
    cout << "лол я изменил значение константы x: " << x << endl;
}
cout << "фак ю, она осталась прежней: " << x << endl;

Вот в расте такое не прокатит. С let декларацией ты можешь так поступать, создавая новый бинд взамен старого, с const'ом так уже не выйдет.

> Ну как кто? Вон выше было "первое же -- это имя, с которым линкеру придётся разбираться".

В примере имя lexically scoped в функции. Оно не появляется в таблице имён линкера, все такие имена разрешаются компилятором.

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

252. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от n00by (ok), 26-Мрт-24, 20:20 
>> Если речь именно о плюсах, а не Си, то нет существенной в данном контексте (особенно, когда нет static и область видимости не очевидна) разницы. И то и то не занимает места в секции данных, будет подставлено непосредственным операндом в машинную инструкцию.
> Не совсем. const int my_constant может быть операндом операции взятия адреса, и
> все такие операции должны возвращать одинаковый адрес.

Я не просто так пишу про static. Наверное, ещё и область видимости стоило бы добавить. Если вернуть адрес автоматической переменной из функции, это UB, но как бы можно, да.

Исходный вопрос, как я понял, сугубо практический. Вроде "я так всегда делал, адрес не брал, и оно в коде ведёт себя как enum".

> В случае же с
> enum { my_constant = 5}, каждое взятие адреса &my_constant может возвращать
> свой собственный адрес. Технически правда, я думаю они всё равно все
> будут одинаковыми, но это не гарантия компилятора, это способ имплементации компилятора.

Вы изначально всё верно писали, но тут принялись мне объяснять лишнее и не туда зашли. Это не lvalue. Если передать my_constant параметром в функцию, то адрес у аргумента получить можно, но это окажется неявно созданная копия.

>> Это в случае переменных со связыванием. Отсюда при отсутствии static и возникает вопрос, а не определяется ли константа вот так
> Тут компилятор тоже должен предоставить константе валидный адрес, другое дело, что если
> оптимизатор достаточно умён, и видя что время жизни ограничено лексическим скоупом,
> он может подметить ситуацию, когда адрес не используется. Такие штуки становятся
> сложнее, если константная переменная доступна для юнита (топ-левел декларация static const
> int), потому что то в чём компиль реально силён, и ещё
> сложнее, если она не ограничена юнитом (там только LTO может помочь,
> теоретически, а практически я не знаю, помогает ли он).

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

>> В Си ничего нет про аллокацию на стеке. Там это называется automatic storage duration, и всякий сишник знает, что стека может вообще не быть.
> Сишное мышление проявляется не в использовании слова "стек", а в озабоченности стораджем
> в ущерб всему остальному. C не проводит чётко разницы между, например,
> переменной, сторейжем ассоциированным с ней, и значением сохранённым в этом сторейже.

Местом хранения озадачиваются только когда оно статичное (что бы инициализировать один раз при вызове функции, что бы экспортировать, или что бы было локально для потока). В остальных случаях оно автоматическое - то есть на выбор транслятора и не важно где. И Си это не плюсы. В Плюсах есть ссылки, у них нет стоража.

> Лол, из-за этого, я когда столкнулся с растом впервые, недели две
> бился головой о клавиатуру, не мог понять логики. Сторейж переменной может
> меняться по ходу дела, компилятор не даёт гарантий на этот счёт,
> значение в строейже может меняться, или сторейж может уходить от одной
> переменной к другой (например когда ты делаешь move: let my_big_value =
> ...; foo(my_big_value); функция foo будет работать с тем же самым куском
> сторейжа, который был ассоциирован с my_big_value, но переменная в ней будет
> другая).

Логика Rust довольно простая. Автор посмотрел на OCaml и его осенила гениальная мысль - почему бы в Си++ не сделать всё const по умолчанию, ведь это разом решит множество проблем (в частности избавит от всяких фокусов вроде возврата ссылки на локальную статическую переменную, что бы скрыть связывание). Но позже почему-то ушёл из проекта.

>[оверквотинг удален]
> my_big_value отправляем в функцию, она может начать менять это значение. А
> вот константа... ты не можешь у неё отнять сторейж, ты не
> можешь изменить значение хранящееся в нём. Ты не можешь "затенить" константу
> другой декларацией, чтобы создать лексическую изменяемость:
> const int x = 5;
> {
>     const int x = 6;
>     cout << "лол я изменил значение константы x: " << x << endl;
> }
> cout << "фак ю, она осталась прежней: " << x << endl;

#include <iostream>

const struct { mutable int x; } X = { 5 };

int main() {
  X.x = 6;
  std::cout << "я действительно изменил значение константы X: " << X.x << std::endl;
}
// не та область видимости
// std::cout << "лол я изменил значение константы x: " << x << std::endl;

Оно в принципе будет работать и с extern const int x, если определить ссылку на константу через const_cast, но придётся менять защиту страницы памяти константной секции ELF-а, что бы не упало при попытке записи. Что бы не заморачиваться, приходится прибегать к фокусам:

struct { const int x; int y; } X = { 5 };

int main() {
  int& xx = const_cast<int&>(X.x);
  xx = 6;
  std::cout << "я действительно изменил значение константы x: " << X.x << std::endl;
}

> Вот в расте такое не прокатит. С let декларацией ты можешь так
> поступать, создавая новый бинд взамен старого, с const'ом так уже не
> выйдет.

Так в том примере две разные переменные с одним именем.

>> Ну как кто? Вон выше было "первое же -- это имя, с которым линкеру придётся разбираться".
> В примере имя lexically scoped в функции. Оно не появляется в таблице
> имён линкера, все такие имена разрешаются компилятором.

Значит нет неявного static, то есть переменная не имеет связывания, не хранится в секции данных. Пока кто-то не пытается взять её адрес, она крякает как enum.

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

257. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от Аноним (-), 27-Мрт-24, 11:30 
> Исходный вопрос, как я понял, сугубо практический. Вроде "я так всегда делал, адрес не брал, и оно в коде ведёт себя как enum".

Ну, как бы это сказать. Мне приходилось брать адрес от литерала, например, ты можешь попробовать сделать:

    foo(&5);

Я не знаю как там C или C++ с этим обходится, rust легко создаст 5 в памяти, и передаст в функцию её адрес. Вот с константой примерно то же самое.

> Если передать my_constant параметром в функцию, то адрес у аргумента получить можно, но это окажется неявно созданная копия.

Try it. Я забавы ради попробовал в rust'е, он мне даёт два одинаковых адреса для &5u32 и &MY_CONSTANT, который был объявлен как const MY_CONSTANT: u32 = 5;

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

> Если видимость единицей трансляции не ограничена, то это внешнее связывание, но extern не написано же.

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

> Логика Rust довольно простая. Автор посмотрел на OCaml и его осенила гениальная мысль - почему бы в Си++ не сделать всё const по умолчанию, ведь это разом решит множество проблем (в частности избавит от всяких фокусов вроде возврата ссылки на локальную статическую переменную, что бы скрыть связывание). Но позже почему-то ушёл из проекта.

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

> Оно в принципе будет работать и с extern const int x, если определить ссылку на константу через const_cast, но придётся менять защиту страницы памяти константной секции ELF-а, что бы не упало при попытке записи.

Йее, я вижу начало доходить потихоньку? Значение переменной, даже константной это значение переменной, её можно поменять, пускай для этого и придётся прибегать ко всяким трюкам, иногда системно-зависимым. Но попробуй в рантайме поменять значение из enum'а.

> Так в том примере две разные переменные с одним именем.

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

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

259. "Выпуск языка программирования 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ообщить модератору

250. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от Аноним (-), 26-Мрт-24, 14:47 
> Если речь именно о плюсах, а не Си, то нет существенной в данном контексте (особенно, когда нет static и область видимости не очевидна) разницы. И то и то не занимает места в секции данных, будет подставлено непосредственным операндом в машинную инструкцию.

Не совсем. const int my_constant может быть операндом операции взятия адреса, и все такие операции должны возвращать одинаковый адрес. В случае же с enum { my_constant = 5}, каждое взятие адреса &my_constant может возвращать свой собственный адрес. Технически правда, я думаю они всё равно все будут одинаковыми, но это не гарантия компилятора, это способ имплементации компилятора.

> Это в случае переменных со связыванием. Отсюда при отсутствии static и возникает вопрос, а не определяется ли константа вот так

Тут компилятор тоже должен предоставить константе валидный адрес, другое дело, что если оптимизатор достаточно умён, и видя что время жизни ограничено лексическим скоупом, он может подметить ситуацию, когда адрес не используется. Такие штуки становятся сложнее, если константная переменная доступна для юнита (топ-левел декларация static const int), потому что то в чём компиль реально силён, и ещё сложнее, если она не ограничена юнитом (там только LTO может помочь, теоретически, а практически я не знаю, помогает ли он).

> В Си ничего нет про аллокацию на стеке. Там это называется automatic storage duration, и всякий сишник знает, что стека может вообще не быть.

Сишное мышление проявляется не в использовании слова "стек", а в озабоченности стораджем в ущерб всему остальному. C не проводит чётко разницы между, например, переменной, сторейжем ассоциированным с ней, и значением сохранённым в этом сторейже. Лол, из-за этого, я когда столкнулся с растом впервые, недели две бился головой о клавиатуру, не мог понять логики. Сторейж переменной может меняться по ходу дела, компилятор не даёт гарантий на этот счёт, значение в строейже может меняться, или сторейж может уходить от одной переменной к другой (например когда ты делаешь move: let my_big_value = ...; foo(my_big_value); функция foo будет работать с тем же самым куском сторейжа, который был ассоциирован с my_big_value, но переменная в ней будет другая).

В расте const декларация -- это имя для _значения_, let декларация -- это имя для переменной, которая может хранить значение, а может и не хранить. let делает _переменную_ неизменной, но нет гарантий что в сторейж никто не будет писать. В том примере выше, когда мы my_big_value отправляем в функцию, она может начать менять это значение. А вот константа... ты не можешь у неё отнять сторейж, ты не можешь изменить значение хранящееся в нём. Ты не можешь "затенить" константу другой декларацией, чтобы создать лексическую изменяемость:

const int x = 5;
{
    const int x = 6;
    cout << "лол я изменил значение константы x: " << x << endl;
}
cout << "фак ю, она осталась прежней: " << x << endl;

Вот в расте такое не прокатит. С let декларацией ты можешь так поступать, создавая новый бинд взамен старого, с const'ом так уже не выйдет.

> Ну как кто? Вон выше было "первое же -- это имя, с которым линкеру придётся разбираться".

В примере имя lexically scoped в функции. Оно не появляется в таблице имён линкера, все такие имена разрешаются компилятором.

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

213. "Выпуск языка программирования Rust 1.77"  +2 +/
Сообщение от Аноним (113), 24-Мрт-24, 05:04 
Если коротко, то у них разная семантика и жизненный цикл.
Ответить | Правка | К родителю #195 | Наверх | Cообщить модератору

216. "Выпуск языка программирования Rust 1.77"  +/
Сообщение от Facemaker (?), 24-Мрт-24, 12:24 
>const требует обязательного указания типа. Логику этого я не совсем понимаю, но думаю что есть причины

Одно из неявных правил, которого придерживаются разработчики языка: "выведение типа — локально". Константы (как и функции) могут быть объявлены на уровне модуля.

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

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




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

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