Здравствуйте, Kolesiki, Вы писали:
K>Самый тупой из всех возможных. K>Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично! K>Даже в плане употребления это намного правильнее. Никому не нужна "длина массива" — она неуклюжа как раз тем, что напрямую с массивом её нельзя использовать — её ВСЕГДА приходится вычитать. А понятие "индекс с конца" как раз и удобен тем, что видимый индекс и есть естественный индекс, как если бы мы считали от начала массива.
Здравствуйте, AlexRK, Вы писали:
A>>Логично, что последний элемент находится перед концом массива, а после или на конце ничего нет. ARK>Тогда настолько же "логично", что первый элемент находится после начала массива, а перед или в начале ничего нет.
Перед началом массива действительно ничего нет, а как только он начался, идёт первый элемент. А как только кончился, снова ничего не идёт.
Здравствуйте, Kolesiki, Вы писали:
A>>Нельзя автоматом — теряется половина смысла. K>Тут согласен, но строго говоря, у меня вообще ни разу такого случая не было, чтобы "по ошибке" я лез переинициализировать целую структуру! Это довольно тупая ошибка и клянусь, если ЭТО для них проблема — вон из профессии! Это далеко не те вещи, о которых надо заботиться программисту.
Необязательно переинициализировать целую структуру. У структуры может быть десяток полей, достаточно в методе пытаться изменить одно и он не сможет быть readonly-методом.
1) У больших структур больше накладных расходов на защитное копирование.
2) Именно у больших структур больше полей, которые тоже могут быть структурами с несколькими уровнями вложенности. В результате затруднительно держать в голове все поля всех структур и помнить, какой метод что и как делает.
3) Именно большие структуры труднее сделать целиком иммутабельными в соответствии с правилами хорошего тона. Но если нельзя всю её объявить readonly, можно дописать readonly её свойствам/методами по-максимуму и поручить следить за этим машине. Её для этого сделали, автоматизировать тупую работу.
---------------------------------------------
индекс от начала массива | 0 1 2 3 4
---------------------------------------------
элементы массива | a b c d e
---------------------------------------------
индекс от конца массива | 4 3 2 1 0
---------------------------------------------
Разверни массив — и получишь индекс с конца. Как иначе-то?
Если иначе — то это не индекс с конца, а что-то другое. А если что-то другое, но при этом визуально похоже на индекс — то это тупизна и костыль, увеличивающий когнитивную нагрузку на ровном месте.
Здравствуйте, alexzzzz, Вы писали:
A>Здравствуйте, Kolesiki, Вы писали:
K>>Индекс ПЕРВОГО элемента массива знают даже дети — 0. abc[0] — первый элемент. Сикарашка "^" нам говорит: а теперь мы считаем элементы с конца. И чтобы взять последний элемент... просто напиши abc[^0]! Это же логично!
A>Смотря, что ты считаешь концом массива. Логично, что последний элемент находится перед концом массива, а после или на конце ничего нет.
Вы рассуждаете о массиве как о некоей линейной вещи, которая лежит в адресном пространстве (чисто сипиписное мышление — на примитивах CPU). Я же смотрю на массив ТОЛЬКО как на некий ряд элементов в пустоте. Что ВНЕ массива — мне не интересно. Соотв. у меня нет "нечто за гранью последнего элемента". Есть последний элемент. Он, как и первый элемент, легко индексируется сосвоего конца логичным индексом 0.
Здравствуйте, alexzzzz, Вы писали:
A>Кто-нибудь пишет такие циклы: A>
for (int i = 0; i <= array.Length - 1; i++)
?
Ваша ошибка кроется в том, что ЛОГИЧЕСКИ вы работаете с "массивом наоборот" (т.е. говоря в коде "я ставлю ^ и значит мы работаем с конца"), а ФИЗИЧЕСКИ эта "крышечка" реализована как array.Length, что в корне неверно! Потому что тогда последний элемент массива должен быть не "^1" (как они нам пытаются всучить), а "^-1"!! Т.е. "взять длину и вычесть один для попадания на последний элемент". ВОТ ГДЕ бестолковое понимание целей послужило кривой реализации.
А всё от того, что они увидели в Ди знак $ (который в ДИАПАЗОНАХ означает именно длину), но попытались превратить его в "логический реверс".
Я ж грю — безалаберное стадо макак может месяцами рассуждать о фичах и всё равно выбрать самый тупой вариант — вот почему так редко пишу им issues — бесполезно, как об стенку горох.
Здравствуйте, AlexRK, Вы писали:
ARK>Если иначе — то это не индекс с конца, а что-то другое. А если что-то другое, но при этом визуально похоже на индекс — то это тупизна и костыль, увеличивающий когнитивную нагрузку на ровном месте.
Вот! Специально подчеркнул ключевой момент. Т.е. a[0] — это индекс. А a[^0] — хрен знает что, построенное на индусячей арифметике и длине массива. Лучше б они вообще не брались за "индексы с конца" — не такая это частая задача, чтобы пихать это в язык. Не говоря о том, что квалификация "пихунов" оставляет желать лучшего.
Здравствуйте, alexzzzz, Вы писали:
ARK>>a[^4] — последний элемент с конца ARK>>a[4] — oops, out of bounds exception, надо a[3]
A>?
Здесь что-то не так?
ARK>>А причем тут индексы элементов? A>Диапазон состоит из пары индексов, которые определяют его начало и конец. Он ими задаётся.
Почему-то слово "индекс" меняет смысл при смене точки отсчета с начала массива на конец. Создается впечатление, что словом "индекс" называют две разные вещи.
Здравствуйте, AlexRK, Вы писали:
ARK>>>a[^4] — последний элемент с конца ARK>>>a[4] — oops, out of bounds exception, надо a[3] A>>? ARK>Здесь что-то не так?
Я не понял, что значит "последний элемент с конца" и как это связано с ^4.
ARK>Почему-то слово "индекс" меняет смысл при смене точки отсчета с начала массива на конец. Создается впечатление, что словом "индекс" называют две разные вещи.
Индекс был равнозначен смещению относительно начала. Когда говорим "смещение", надо уточнить, относительно чего. Когда говорим "индекс", подразумевается, что от начала. Начало массива совпадает с началом его первого элемента, смещение нулевое. У элемента с индексом N смещение N относительно начала массива.
Так было всегда. Сейчас добавилась возможность изменить точку отсчёта, а числовые индексы как были по сути смещениями, так и остались.
Жирные полосочки — это индексы/смещения.
У float с индексом 2 начало смещено на 2 относительно начала массива. Это смещение в "единицах float". Если умножить на 4, будет 8 — смещение в "единицах byte" или индекс первого байта из этого float.
Float с индексом 7 — последний. У него смещение 7 в "единицах float" относительно начала массива или 1 относительно конца. Если эту 1 умножить на 4, будет смещение 4 в "единицах byte" относительно конца. 7*4 -> 28 и ^1*4 -> ^4 указывают на один и тот же байт, начальный байт последнего float.
Kolesiki может по привычке искать начало последнего элемента через length-1, если нравятся отрицательные числа, но оператор ^ позволяет записать это короче: ^1. Крышечка — это не сам конец массива, это унарный оператор такой, возвращающий значение типа Index, привязанное к концу.
Раньше существовала путаница между "индексами" (которые считаются с нуля) и "порядковыми номерами" (первый, второй, ...). Говоришь "пятый элемент" и непонятно, это индекс или порядковый номер. Сейчас к этому добавятся ещё индексы типа ^5, которые индексы в смысле "значения типа Index". Если продолжать всё считать от начала, то ничего не изменится; а считать от конца непривычно никому, надо привыкнуть. Но когда модель мира в голове подтверждается наблюдениями, то это проще, чем когда они противоречат.
Здравствуйте, alexzzzz, Вы писали:
ARK>>>>a[^4] — последний элемент с конца ARK>>>>a[4] — oops, out of bounds exception, надо a[3] A>>>? ARK>>Здесь что-то не так? A>Я не понял, что значит "последний элемент с конца" и как это связано с ^4.
Ну, то и значит. Последний элемент с конца это последний элемент, если вести отсчет с конца. Я не знаю, как иначе объяснить.
A>Индекс был равнозначен смещению относительно начала. Когда говорим "смещение", надо уточнить, относительно чего. Когда говорим "индекс", подразумевается, что от начала. Начало массива совпадает с началом его первого элемента, смещение нулевое. У элемента с индексом N смещение N относительно начала массива.
Что такое "начало" и "конец"? Если "начало" — это "адрес первого элемента", а конец — это "адрес последнего элемента", то конец массива — это "Length — 1", он совпадает с адресом последнего элемента и смещение относительно конца должно быть тоже нулевое.
A>Так было всегда. Сейчас добавилась возможность изменить точку отсчёта, а числовые индексы как были по сути смещениями, так и остались.
Но "смещение относительно конца" сделали неправильное.
A>У float с индексом 2 начало смещено на 2 относительно начала массива. Это смещение в "единицах float". Если умножить на 4, будет 8 — смещение в "единицах byte" или индекс первого байта из этого float.
ОК.
A>Float с индексом 7 — последний. У него смещение 7 в "единицах float" относительно начала массива или 1 относительно конца.
У него смещение в "единицах float" относительно конца должно быть 0, а не 1.
A>Если эту 1 умножить на 4, будет смещение 4 в "единицах byte" относительно конца. 7*4 -> 28 и ^1*4 -> ^4 указывают на один и тот же байт, начальный байт последнего float.
Что за странная арифметика? Чему равно ^1 и ^4? Почему ^4 = 28?
A>Kolesiki может по привычке искать начало последнего элемента через length-1, если нравятся отрицательные числа, но оператор ^ позволяет записать это короче: ^1. Крышечка — это не сам конец массива, это унарный оператор такой, возвращающий значение типа Index, привязанное к концу.
Только оператор ^ — это не индекс, а какая-то странная сущность.
Здравствуйте, AlexRK, Вы писали:
ARK>>>>>a[^4] — последний элемент с конца ARK>>>>>a[4] — oops, out of bounds exception, надо a[3] A>>>>? ARK>>>Здесь что-то не так? A>>Я не понял, что значит "последний элемент с конца" и как это связано с ^4.
ARK>Ну, то и значит. Последний элемент с конца это последний элемент, если вести отсчет с конца. Я не знаю, как иначе объяснить.
Последний элемент с конца — это первый элемент (если я правильно понимаю в слова). Если ^4 — первый элемент, значит от конца коллекции до её начала надо сделать 4 шага, значит в ней 4 элемента: 0, 1, 2 и 3.
ARK>Что такое "начало" и "конец"?
Если в чистом виде, то абстракция — на картинке выше нарисованы жирными линиями. Если в практическом плане, то да, скорее адрес. Как и «элемент» — абстрактная сущность, а на практике последовательность байт.
ARK>Если "начало" — это "адрес первого элемента", а конец — это "адрес последнего элемента",
В этом месте проблема.
Начало массива ― адрес первого байта массива, совпадает с адресом первого байта первого элемента. Тут трудностей не возникает.
Конец же массива не может указывать на данные внутри массива. Это не адрес последнего элемента, потому что тогда данные элемента могут лежать за концом массива — глупость получается. Единственный рациональный вариант, который работает для однобайтовых и многобайтовых элементов, считать концом массива адрес первого байта за пределами последнего элемента массива. Как бонус, конец последнего элемента совпадает с концом всего массива.
Так обычно и принято задавать диапазоны: начало ― адрес/индекс/указатель на первый элемент, конец ― адрес/индекс/указатель на нечто после последнего элемента. Inclusive start, exclusive end.
Ну или второй популярный вариант: адрес/индекс/указатель на начало последовательности и количество элементов. Всю жизнь в NET API использовали второй вариант. Но по сути это одно и то же, переводится друг в друга одной арифметической операцией: start + length = end или end — start = length. Вот даже формулки простые и логичные.
ARK>Только оператор ^ — это не индекс, а какая-то странная сущность.
Обычный унарный оператор, только новый применительно к целым числам.
Здравствуйте, alexzzzz, Вы писали:
ARK>>Ну, то и значит. Последний элемент с конца это последний элемент, если вести отсчет с конца. Я не знаю, как иначе объяснить. A>Последний элемент с конца — это первый элемент (если я правильно понимаю в слова). Если ^4 — первый элемент, значит от конца коллекции до её начала надо сделать 4 шага, значит в ней 4 элемента: 0, 1, 2 и 3.
Эту логику я не понимаю.
Почему нельзя сказать "если ^4 — первый элемент, значит, от конца коллекции до её начала надо сделать 5 шагов, значит, в ней 5 элементов: 0, 1, 2, 3 и 4"?
Почему нельзя сказать "если ^4 — первый элемент, значит, от конца коллекции до её начала надо сделать 4 шага, значит, в ней 4 элемента: 1, 2, 3 и 4"?
Вопросы риторические, конечно. Ответ "патамушта так сделали". Но консистентности за этим не видно. И, судя по всему, не только мне.
A>Конец же массива не может указывать на данные внутри массива.
Но ведь начало массива указывает на данные внутри массива, почему же конец не может?
A>Это не адрес последнего элемента, потому что тогда данные элемента могут лежать за концом массива — глупость получается.
Смотря как трактовать термин "конец массива". Массив — это абстракция.
A>Единственный рациональный вариант, который работает для однобайтовых и многобайтовых элементов, считать концом массива адрес первого байта за пределами последнего элемента массива. Как бонус, конец последнего элемента совпадает с концом всего массива.
Не вижу, чем этот вариант рациональнее варианта "считать концом массива адрес последнего элемента". Как бонус, индексы с конца начинаются с 0, а не с 1.
A>Так обычно и принято задавать диапазоны: начало ― адрес/индекс/указатель на первый элемент, конец ― адрес/индекс/указатель на нечто после последнего элемента. Inclusive start, exclusive end.
Вот в этой встроенной асимметричности как раз и корень проблемы.
A>Ну или второй популярный вариант: адрес/индекс/указатель на начало последовательности и количество элементов. Всю жизнь в NET API использовали второй вариант. Но по сути это одно и то же, переводится друг в друга одной арифметической операцией: start + length = end или end — start = length. Вот даже формулки простые и логичные.
Угу, только вот первый элемент a[0], а последний a[^1]. Просто и логично.
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, alexzzzz, Вы писали:
A>>Единственный рациональный вариант, который работает для однобайтовых и многобайтовых элементов, считать концом массива адрес первого байта за пределами последнего элемента массива. Как бонус, конец последнего элемента совпадает с концом всего массива.
ARK>Не вижу, чем этот вариант рациональнее варианта "считать концом массива адрес последнего элемента". Как бонус, индексы с конца начинаются с 0, а не с 1.
В соответствии с этим вариантом "считать концом массива адрес последнего элемента" выходит что последний элемент лежит за концом массива, т.е. массив не содержит последний элемент. И это ассиметрично с тем, что первый элемент (как и все, кроме последнего) все-таки лежит внутри массива, а не снаружи.