OberonCore https://forum.oberoncore.ru/ |
|
Массивы нулевой длины https://forum.oberoncore.ru/viewtopic.php?f=27&t=6374 |
Страница 1 из 5 |
Автор: | Info21 [ Пятница, 05 Апрель, 2019 04:31 ] |
Заголовок сообщения: | Массивы нулевой длины |
Есть такое полезное правило: процедура должна корректно обрабатывать нулевой случай (пустой список, пустое множество и т.п.). Практическая полезность имеет тут место быть примерно по той же причине, что и в случае цифры нуль, хотя и не в таком масштабе. Несколько раз возникало желание, чтобы были возможны массивы нулевой длины, -- как раз такой "нулевой случай". Желание на первый взгляд странное, но возражения против него подобны простодушному возражению против нуля: зачем иметь обозначение для отсутствия подсчитываемых предметов )) Предположим, что определение языка ослабляется так, чтобы разрешить массивы нулевой длины. Впечатление, что это никак не повлияет на существующий софт -- или я чего-то не вижу? Кстати, вопрос можно было бы пустить по линии верификации программ. PS На вопрос повлиял свежий коммент С.Волкова о том, что он работает с Обероном, взыскуя научности )) |
Автор: | Валерий Лаптев [ Пятница, 05 Апрель, 2019 08:01 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
С научной точки зрения - все правильно. Вопросы - в реализации. Статический массив нулевой длины должен иметь какой-то адрес. Проверка индексов, на мой взгляд, очевидно, для такого массива должна быть при компиляции. Динамический массив - тоже должен иметь какой-то адрес. И замечу, что все динамические массивы нулевой длины должны иметь РАЗНЫЕ адреса. Проверка индекса такого для массива возможна ТОЛЬКО во время компиляции. Недавно в одной лабе на С++ пацан сделал массив нулевой длины. С++ это теоретически разрешает. В лабе требовалось добавлять по 1 элементу в массив. Вот он создает массив нулевой длины, передает его в качестве параметра в функцию. Функция делает новый массив размером +1, переписывает туда переданный массив и последним размещает новый элемент. Адрес нового массива возвращается из функции. Прога не работала. Я смотрел адреса. С++ нулевым массивам присваивал адреса, которые вызывают access violation. Посоветовал пацану не выпендриваться, прочитать стандарт - может быть, там undifined behavior возникает? Но пацану было читать лень, он просто стал создавать массив ненулевой длины... |
Автор: | Info21 [ Пятница, 05 Апрель, 2019 09:59 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Спасибо, но у динамического массива есть уникальный дескриптор. И статической проверки компилятором в этом случае быть не может. См. какой-нибудь цикл по массиву, передаваемому в качестве VAR параметра. Весь смысл здесь в том, чтобы код не зависел от длины массива, в том числе в случае нуля. |
Автор: | Илья Ермаков [ Пятница, 05 Апрель, 2019 10:24 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Поддерживаю. Конечно, это обретает смысл в условиях параметров - открытых массивов. В С непонятно, нафига козе баян ) В КП, кстати, я не вижу проблем к этому. У динамических массивов в их заголовке блока может стоять длина 0, корректно работало (создать нельзя нулевой длины, потом поставить можно - мы делали SetLength для дин. массивов - который многие на этом форуме используют - и там допускается и 0). С открытыми массивами - тоже почти всё ОК с приёмом нуля (почему почти - скажу дальше). Вот пример: Код: MODULE Krl_devLangArr0; IMPORT SYSTEM, StdLog; PROCEDURE P (VAR x: ARRAY OF INTEGER); VAR i: INTEGER; BEGIN StdLog.Int(LEN(x)); i := 0; x[i] := 1 END P; PROCEDURE Do*; VAR x: ARRAY 1 OF INTEGER; BEGIN P(SYSTEM.THISARRAY(SYSTEM.ADR(x[0]), 0)); END Do; END Krl_devLangArr0. Всё корректно. В лог печатается 0, защита границ срабатывает, в окне трэпа виден массив нулевого размера: Вложение: Снимок экрана от 2019-04-05 10-16-33.png [ 11.42 КБ | Просмотров: 8705 ] КосяГ проявляется, если обращаться к массиву по константному индексу: Код: PROCEDURE P (VAR x: ARRAY OF INTEGER); VAR i: INTEGER; BEGIN StdLog.Int(LEN(x)); x[0] := 1 END P; На x[0] - пропускает почему-то. На x[1] - уже нет, трэпует. Кто спинным мозгом ассемблер курит, может помозговать. Вот декодер для BEGIN x[0] := 1 END P: Вложение: А вот для BEGIN i := 0; x[i] := 1; END P: Вложение:
|
Автор: | Comdiv [ Пятница, 05 Апрель, 2019 11:59 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Info21 писал(а): Предположим, что определение языка ослабляется так, чтобы разрешить массивы нулевой длины. Согласен, что массив 0-й длины может быть полезен, но его введение всё-таки может повлиять на тот код, который безусловно обращается к 0-му элементу массива исходя из того, что длина массива > 0.Впечатление, что это никак не повлияет на существующий софт -- или я чего-то не вижу? Валерий Лаптев писал(а): Статический массив нулевой длины должен иметь какой-то адрес Поскольку речь не о Си, то адреса отличные от 0 не нужны. Если всё же нужны, то для чего?
... Динамический массив - тоже должен иметь какой-то адрес. И замечу, что все динамические массивы нулевой длины должны иметь РАЗНЫЕ адреса. |
Автор: | Trurl [ Пятница, 05 Апрель, 2019 14:36 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Есть еще код типа a[LEN(a)-1] := 0X. Да и вообще, ни одна процедура из Strings не выдержит массива нулевой длины. |
Автор: | Илья Ермаков [ Пятница, 05 Апрель, 2019 17:09 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Ну, де факто массив символов как массив символов и массив символов как строка и так представляют собой два разных семантических типа в КП. Т.е. глядя на нечто, что объявлено как ARRAY OF CHAR, мы должны получить откуда-то дополнительную информацию, по какому соглашению используется этот ARRAY OF CHAR. Можем ли мы применить к нему строковые операции, не получив выход за его границы. |
Автор: | Artyemov [ Пятница, 05 Апрель, 2019 19:47 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Илья Ермаков писал(а): Т.е. глядя на нечто, что объявлено как ARRAY OF CHAR... Максимально допустимая длина? |
Автор: | Info21 [ Пятница, 05 Апрель, 2019 20:07 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Trurl писал(а): ни одна процедура из Strings не выдержит массива нулевой длины. String-значение требует массива длиной не менее 1, так что давать модулю Strings массив нулевой длины -- заведомая ошибка.Поэтому и правильно, что не выдержат. Но пустые strings они как раз, если не ошибаюсь, выдерживают. |
Автор: | Илья Ермаков [ Суббота, 06 Апрель, 2019 00:06 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Artyemov писал(а): Илья Ермаков писал(а): Т.е. глядя на нечто, что объявлено как ARRAY OF CHAR... Максимально допустимая длина? Имею в виду параметр - открытый массив. Про "можем ли применить строковые операции": - применение $ или + к произвольному ARRAY OF CHAR чревато непредсказуемым поведением (если там не строка, то как повезёт с наличием нуля); - т.е. семантика конкретного ARRAY OF CHAR зависит от того, как он использован (под строку или не под строку). |
Автор: | arlean1 [ Вторник, 09 Апрель, 2019 22:48 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
В 2004 г. это оценивалось так: Цитата: Okay, you may say, then why not use a zero-length array instead of a 1-length array? Because time travel has yet to be perfected. Раймонд Чен https://devblogs.microsoft.com/oldnewthing/?p=38043 |
Автор: | Info21 [ Среда, 10 Апрель, 2019 09:30 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
arlean1 писал(а): В 2004 г. это оценивалось так: Ещё раз: так же, как нуль даёт возможность "регуляризовать" алгоритмы арифметики, так же, как цикл why оказывается в целом самым удобным ровно потому, что допускает повторение нуль раз, так же, как рекурсивные процедуры, обрабатывающие "нулевой случай", приводят к более компактным и ясным программам, чем в противном случае, -- совершенно в той же струе лежат наблюдавшиеся ситуации, где допущение массивов нулевой длины "регуляризовало" бы код. По умолчанию программа должна корректно обрабатывать "нулевой случай". Правило базовой техники программирования. Вопрос о том, почему оно не распространено на массивы. |
Автор: | Валерий Лаптев [ Среда, 10 Апрель, 2019 10:40 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
В С++ мы просто работаем с контейнером vector - он это, естественно, позволяет. Я уж и забыл, когда последний раз работал со встроенными массивами. Может быть, просто стоит реализовать подобный контейнер? |
Автор: | Владимир Ситников [ Среда, 10 Апрель, 2019 10:56 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Валерий Лаптев писал(а): В С++ мы просто работаем с контейнером vector - он это, естественно, позволяет. Я уж и забыл, когда последний раз работал со встроенными массивами. Может быть, просто стоит реализовать подобный контейнер? Ни в коем случае. Массивы нулевой длины это угроза надёжности языка. Вот, например, такие массивы возможны в Java, и сами видите где этот язык сейчас. |
Автор: | Rifat [ Среда, 10 Апрель, 2019 12:27 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Info21 писал(а): arlean1 писал(а): В 2004 г. это оценивалось так: Ещё раз: так же, как нуль даёт возможность "регуляризовать" алгоритмы арифметики, так же, как цикл why оказывается в целом самым удобным ровно потому, что допускает повторение нуль раз, так же, как рекурсивные процедуры, обрабатывающие "нулевой случай", приводят к более компактным и ясным программам, чем в противном случае, -- совершенно в той же струе лежат наблюдавшиеся ситуации, где допущение массивов нулевой длины "регуляризовало" бы код. По умолчанию программа должна корректно обрабатывать "нулевой случай". Правило базовой техники программирования. Вопрос о том, почему оно не распространено на массивы. Нулевой случай не всегда должен обрабатываться как нормальный случай. Разыменовывать нулевой указатель нельзя. Приводить нулевой указатель к другому типу (по крайней мере в Oberon-07) нельзя. Делить на нуль нельзя Если будут массивы нулевой длины, то к ним нельзя будет обращаться через оператор обращения к элементу массива [] ни с каким значением. То есть по сути оператор [] для них будет запрещен. Получается, что ко всем массивам можно будет обращаться по оператору [] (в заданных пределах, чтобы не выйти за границы массива), а к операторам с нулевой длиной нельзя. Если уж очень хочется, то можно же легко создать свой тип, например, Vector, который сможет быть нулевой длины. P.S. В книге Вирта читал про поиск с барьером, когда, пишут не: Код: i := 0; WHILE (i < Number) & (array[i] # searchingValue) DO i := i + 1; END; а пишут: Код: array[Number] := searchingValue; i := 0; WHILE array[i] # searchingValue DO i := i + 1; END; При этом необходимо чтобы массив был на 1 элемент больше, чем требуется хранить элементов. И по аналогии с этим Вы всегда можете использовать массивы на 1 элемент больше и тогда массивом нулевой длины будет реальный массив из 1 элемента. |
Автор: | Ярослав Романченко [ Среда, 10 Апрель, 2019 12:33 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Владимир Ситников писал(а): Ни в коем случае. Массивы нулевой длины это угроза надёжности языка. Где можно почитать про проблемы в Java, связанные с массивами нулевой длины?Вот, например, такие массивы возможны в Java, и сами видите где этот язык сейчас. И речь вообще-то Валерий завёл об обобщённых контейнерах, которые теоретик Компонентного Паскаля Шиперский предложил, но они так и остались нереализованными. |
Автор: | Валерий Лаптев [ Среда, 10 Апрель, 2019 15:07 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Rifat писал(а): При этом необходимо чтобы массив был на 1 элемент больше, чем требуется хранить элементов. И по аналогии с этим Вы всегда можете использовать массивы на 1 элемент больше и тогда массивом нулевой длины будет реальный массив из 1 элемента. В С++ в контейнерах просто есть некий фиктивный элемент после последнего элемента, который нужен для легализации итератора end. Я об этом довольно подробно разъяснял в своей книжке... Если в Обероне сделать такой же контейнер с невидимым фиктивным элементом, то должно все получиться. Кстати, для пустого вектора попытка обратиться по индексу заканчивается аварийно. Это - нормальное поведение. Но зачем тащить в язык, если можно реализовать в библиотеке? |
Автор: | PSV100 [ Среда, 10 Апрель, 2019 18:47 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Валерий Лаптев писал(а): ... Недавно в одной лабе на С++ пацан сделал массив нулевой длины. С++ это теоретически разрешает. В лабе требовалось добавлять по 1 элементу в массив. Вот он создает массив нулевой длины, передает его в качестве параметра в функцию. Функция делает новый массив размером +1, переписывает туда переданный массив и последним размещает новый элемент. Адрес нового массива возвращается из функции. Прога не работала. Я смотрел адреса. С++ нулевым массивам присваивал адреса, которые вызывают access violation. ... Скорее, C++ автоматически не выделяет память и не присваивает адреса нулевым массивам. В противном случае теряется смысл как таковой их применения. Если необходимо выделение памяти, то таково осуществляется для внешних по отношению к массиву объектов (явные указатели на массив или структуру, его содержащую, и т.п.). См., например (плюс там комментарии к ответу): https://ru.stackoverflow.com/questions/297649/%D0%9C%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D1%8B-%D0%BD%D1%83%D0%BB%D0%B5%D0%B2%D0%BE%D0%B9-%D0%B4%D0%BB%D0%B8%D0%BD%D1%8B# |
Автор: | PSV100 [ Среда, 10 Апрель, 2019 18:50 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Валерий Лаптев писал(а): В С++ мы просто работаем с контейнером vector - он это, естественно, позволяет. Я уж и забыл, когда последний раз работал со встроенными массивами. Может быть, просто стоит реализовать подобный контейнер? [...] Но зачем тащить в язык, если можно реализовать в библиотеке? Всё же, первично то, что язык должен позволять реализовывать библиотеки. Вряд ли какой-то единственный vector может оказаться предельно общим, т.е. единственным решением для всех случаев в универсальном ЯВУ (если всё же эффективность не игнорировать). К примеру, если понадобится контейнер как "вектор векторов" (таблица), то некий стандартный vector может не удовлетворить потребности. Использование структур/записей в качестве хранимых элементов (строка таблицы) вектора/динамического массива может оказаться нерациональным для распределения памяти, неэффективным для применения определенных политик доступа. К тому же возможно определение структур только в runtime (состав столбцов задаётся динамически во время выполнения программы). Или же необходимо организовать постраничное управление памятью и т.д. В итоге, необходимы разные реализации всякого разного, и реализации эффективные. Соответственно, и язык должен способствовать. Не в курсе, как такие вопросы решаемы в Оберон-е, ещё и во взаимодействии с мусорщиком (к слову, те же хаки над статическими массивами нулевой длины хоть как-то упрощают жизнь). |
Автор: | PSV100 [ Среда, 10 Апрель, 2019 19:05 ] |
Заголовок сообщения: | Re: Массивы нулевой длины |
Info21 писал(а): Ещё раз: так же, как нуль даёт возможность "регуляризовать" алгоритмы арифметики, так же, как цикл why оказывается в целом самым удобным ровно потому, что допускает повторение нуль раз, так же, как рекурсивные процедуры, обрабатывающие "нулевой случай", приводят к более компактным и ясным программам, чем в противном случае, -- совершенно в той же струе лежат наблюдавшиеся ситуации, где допущение массивов нулевой длины "регуляризовало" бы код. По умолчанию программа должна корректно обрабатывать "нулевой случай". Правило базовой техники программирования. Вопрос о том, почему оно не распространено на массивы. Валерий Лаптев писал(а): С научной точки зрения - все правильно. Вопросы - в реализации. Статический массив нулевой длины должен иметь какой-то адрес. Проверка индексов, на мой взгляд, очевидно, для такого массива должна быть при компиляции. ... Возможно, ключевое в том, что есть "массив нулевой длины", и что есть тогда "правильно с научной точки зрения". Кстати, в основных императивных языках программирования по историческим причинам в итоге получился какой-то казус в массивах. Использовать формы декларации динамических/открытых массивов не получится в тех случаях, когда применяют статические массивы (а точнее -- псевдомассивы) нулевой длины (не должно быть никаких скрытых структур-дескрипторов, содержащих длину и прочие возможные метаданные и т.п., контекст управления условными метаданными находится вовне таких объектов). Ведь, что Си-шная форма аля: my_data_t data[0] , что ещё более загадочная FreePascal/Delphi-форма аля: data: array[0..0] of TMyData по сути "с научной точки зрения" некорректны. Указание нуля для измерения массива есть декларация отсутствия этого измерения. Нуль-мерный массив по определению есть скаляр (фактически, не есть массив). Илья Ермаков писал(а): У динамических массивов в их заголовке блока может стоять длина 0, корректно работало (создать нельзя нулевой длины, потом поставить можно - мы делали SetLength для дин. массивов - который многие на этом форуме используют - и там допускается и 0). Видимо, может быть и были какие-то идеологические заморочки с тем, что нельзя создавать массив нулевой длины через new. Мол нельзя задать нуль-мерный массив (или "отменить" (т.е. не указать) какое-то измерение из возможных). А установка длины для одномерного массива-вектора (иными словами, с уже предварительно определенным/введённым измерением, т.е. абстрактный "программистский" массив с неопределенными измерениями до new "превратился" в вектор после new) есть мол декларация нуль-вектора (хотя, скорее, хрень какая-то в итоге). Со стороны "математической научности" показательны языки ML-семейства, где массивы выражаются через форму степени. Массив как кортеж, например, из трёх элементов типа "a" структурно задаётся через произведение (логическое "и"): "a * a * a", что эквивалентно: "a^3". Если указать нулевую степень (для любого типа), то "по-научному" уже нет никакого массива и возникает универсальный тип unit (единица), что эквивалентно пустым скобкам "()". Аналогично введены пустые скобки для списков "[]", для векторов "[| |]" и пр. Именно такие "пустые" константные объекты (с возможностью сопоставления объектов с ними) соответствуют "научным" выражениям пустого множества, нуль-вектора и т.д. (где-то возможны непосредственно юникод-символы пустого множества и пр.). Видимо, всё-таки, в рамках вопросов реализации для поддержки "научной точки зрения" желательны константные выражения для массивов, где пустая форма аля "[]" задаёт частный случай нуль-вектора в явном виде. А реализация в языке "правильных" динамических массивов, которые не содержат ничего лишнего, не требуют никакой памяти при нулевых размерах, и нет никаких скрытых вспомогательных структур, плюс контроль доступа (отключаемый при необходимости) со стороны компилятора -- вопрос непростой, однако. Видимо, нужны техники аля "регионов" в стиле некоторых ML-диалектов (и некоторых приёмов из Rust, пришедших из ML), может быть потребуются аля "дискриминанты" записей как в Ada, и пр. Путь не для Оберонов, видимо. |
Страница 1 из 5 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |