Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, samius, Вы писали:
S>>Но совпадающие границы у пустого массива — вполне приличная абстракция. Лучше, чем другие варианты, как по мне.
ARK>Ну а все же — почему лучше считать [2, 2] пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?
Я тут вижу один элемент — двухэлементный кортеж.
Здравствуйте, samius, Вы писали:
S>>>Но совпадающие границы у пустого массива — вполне приличная абстракция. Лучше, чем другие варианты, как по мне.
ARK>>Ну а все же — почему лучше считать [2, 2] пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество? S>Я тут вижу один элемент — двухэлементный кортеж.
Хорошо. Почему лучше считать "2 .. 2" пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, samius, Вы писали:
ARK>Хорошо. Почему лучше считать "2 .. 2" пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?
Тут все-таки зависит от контекста. Точнее, от ширины элемента. На числовой прямой у нас элементы (числа) не имеют ширины, поэтому [2..2] там вырожденный одноэлементный диапазон. Но когда у элемента есть ненулевая ширина, то по понятным причинам в диапазоне 2..2 не поместится ни одного элемента. Можно даже считать это [2.0 .. 2.0]
Здравствуйте, samius, Вы писали:
ARK>>Хорошо. Почему лучше считать "2 .. 2" пустой последовательностью, чем последовательностью с одним элементом? В чем преимущество?
S>Тут все-таки зависит от контекста. Точнее, от ширины элемента. На числовой прямой у нас элементы (числа) не имеют ширины, поэтому [2..2] там вырожденный одноэлементный диапазон. Но когда у элемента есть ненулевая ширина, то по понятным причинам в диапазоне 2..2 не поместится ни одного элемента. Можно даже считать это [2.0 .. 2.0]
От ширины можно абстрагироваться, считать все элементы атомарными. Это вопрос абстракции. Можно с равным успехом принять 2..2 за диапазон длиной как 0 элементов, так и 1 элемент.
У Дейкстры я увидел два аргумента в пользу первого варианта:
1) можно получить длину без прибавления "1";
2) пустой диапазон представляется "уродливо".
Я нахожу оба этих аргумента несостоятельными — длину надо получать не жонглированием границ диапазонов, а функцией "length" (лучше и читабельность, и поддержка), а "уродлив", на мой взгляд, как раз-таки пустой диапазон в виде "2 .. 2" (опять же, для читабельности и поддержки пустой диапазон проверить можно и нужно соответствующей функцией).
Все это — тяжелое наследие жонглирования битами из С. Зачем на высоком уровне это нужно — пока понять не могу.
advantage that the difference between the bounds as mentioned equals the length of the subsequence
ARK>С одной стороны верно, с другой — в математике испокон веку длина диапазона равна (end — start + 1).
Так «в математике» и нумерация часто с единицы начинается. В математике не приходится много возиться с буферами. А в программировании приходится, и там принят подход (start, endExclusive) или (start, count), где endExclusive = start + count. Без ±1. Если это не дремучий Фортран или Паскаль. Полузакрытые интервалы удобно конкатенировать (приставлять рядышком), в них можно выразить пустую последовательность, они не подвержены «ошибкам на единицу».
Consider now the subsequences starting at the smallest natural number: inclusion of the upper bound would then force the latter to be unnatural by the time the sequence has shrunk to the empty one.
ARK>Да и идея выражать пустой диапазон индексами довольно маразматична сама по себе, ИМХО.
Нет, это очень изящная и практичная идея. Невозможность в закрытом интервале выразить пустую последовательность — это серьёзный недостаток.
Здравствуйте, Qbit86, Вы писали:
Q>В математике не приходится много возиться с буферами. А в программировании приходится, и там принят подход (start, endExclusive) или (start, count), где endExclusive = start + count.
Я бы сказал скорее не "в программировании", а "в низкоуровневом жонглировании битами", что составляет не очень большую часть программирования.
Q>Полузакрытые интервалы удобно конкатенировать (приставлять рядышком)
А закрытые почему нельзя? range1.Concat(range2) или range1 + range2
Q>в них можно выразить пустую последовательность
range.IsEmpty()
Q>они не подвержены «ошибкам на единицу».
range.Length()
ARK>>Да и идея выражать пустой диапазон индексами довольно маразматична сама по себе, ИМХО. Q>Нет, это очень изящная и практичная идея. Невозможность в закрытом интервале выразить пустую последовательность — это серьёзный недостаток.
Не вижу особого смысла в этой идее. Можно хотя бы иллюстративный пример задачи, которую она изящно и практично решает?
Здравствуйте, AlexRK, Вы писали:
ARK>range1.Concat(range2) или range1 + range2 ARK>range.IsEmpty() ARK>range.Length()
Это всё вообще мимо кассы. Это внешний API. Как он устроен внутри? Как рейнджи создаются?
ARK>Можно хотя бы иллюстративный пример задачи, которую она изящно и практично решает?
Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D.
Правая граница не выводится. Согласно документации:
Parameters:
B begin The starting value.
E end The value that serves as the stopping criterion. This value is not included in the range.
— https://dlang.org/phobos/std_range.html#iota
Здравствуйте, Qbit86, Вы писали:
ARK>>range1.Concat(range2) или range1 + range2 ARK>>range.IsEmpty() ARK>>range.Length() Q>Это всё вообще мимо кассы. Это внешний API. Как он устроен внутри? Как рейнджи создаются?
Это API рангов, обесценивающий рассуждения о нужности полуоткрытых диапазонов. Как он устроен внутри, не имеет значения — это деталь реализации. Создавать диапазон можно или как a..b, или через функцию а-ля CreateRange(a, b).
ARK>>Можно хотя бы иллюстративный пример задачи, которую она изящно и практично решает? Q>Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D.
На D я уже приводил примеры выше, но у него не закрытые диапазоны.
Пример закрытого диапазона выглядит так же, как и пример полуоткрытого. Я просто пока не очень понял, в чем "изящество и практичность" полуоткрытых диапазонов. Если исключить низкоуровневое жонглирование битами, где оно может быть полезно, как и адресная арифметика.
Здравствуйте, Qbit86, Вы писали:
Q>>Не, давай теперь ты примеры. На тех мифических языках, где в стандартных API рейнджи задаются закрытыми диапазонами. Начнём с D. Q>Ладно, я сам: Q>Правая граница не выводится. Согласно документации:
Я нигде не утверждал, что в D закрытые диапазоны. Там просто нет сбивающих с толку "индексов с конца". Это две разные вещи, хотя и смежные.
Здравствуйте, AlexRK, Вы писали:
ARK>Это API рангов, обесценивающий рассуждения о нужности полуоткрытых диапазонов. Как он устроен внутри, не имеет значения — это деталь реализации.
Так а зачем тогда вообще притянули за уши сравнение с рангами в D? В C# сто лет уже такие ранги, называются IEnumerable<T>/Linq. Новые Index/Range — не про это.
ARK>Создавать диапазон можно или как a..b, или через функцию а-ля CreateRange(a, b).
И в обоих случаях правая граница не включается, правильно?
Parameters:
B begin The starting value.
E end The value that serves as the stopping criterion. This value is not included in the range.
— https://dlang.org/phobos/std_range.html#iota
ARK>Если исключить низкоуровневое жонглирование битами, где оно может быть полезно, как и адресная арифметика.
Вот мне недавно нужно было отформатировать кучу значений разных типов. И, чтобы не аллоцировать кучу строк, я форматировал всё в один общий массив char'ов. (В .NET Standard 2.1 для этого недавно появился API на Span'ах.) И размечен этот буфер аналогами ArraySegment, каждый внутри представлен парой (offset, count) с переходом в [start, end) при итерации.
И да, иногда некоторые значения — пустые строки, тогда их разметка — это пара (offset, 0) или [start, start) при итерации. Положение этого диапазона, хоть и пустого, в результирующем буфере не забывается, это тоже может использоваться.
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, samius, Вы писали:
S>>Тут все-таки зависит от контекста. Точнее, от ширины элемента. На числовой прямой у нас элементы (числа) не имеют ширины, поэтому [2..2] там вырожденный одноэлементный диапазон. Но когда у элемента есть ненулевая ширина, то по понятным причинам в диапазоне 2..2 не поместится ни одного элемента. Можно даже считать это [2.0 .. 2.0]
ARK>От ширины можно абстрагироваться, считать все элементы атомарными. Это вопрос абстракции. Можно с равным успехом принять 2..2 за диапазон длиной как 0 элементов, так и 1 элемент.
Можно и сантиметры считать атомарными, с учетом того что расстояние между соседними всегда фиксированное. Но зачем?
ARK>Все это — тяжелое наследие жонглирования битами из С. Зачем на высоком уровне это нужно — пока понять не могу.
Затем, что жонглирование битами уже использовало старую абстракцию измерения, которая была задолго до битов. Затрудняюсь даже сказать, за сколько (тысячелетий).
Здравствуйте, Qbit86, Вы писали:
Q>Так а зачем тогда вообще притянули за уши сравнение с рангами в D?
Мне нравится в D то, что нет индекса с конца — есть символ "$", обозначающий конец массива (просто сокращение от длины). И, как следствие, нет некрасивой асимметричности "первый элемент a[0], последний элемент a[^1]".
ARK>>Создавать диапазон можно или как a..b, или через функцию а-ля CreateRange(a, b). Q>И в обоих случаях правая граница не включается, правильно?
Прикол в том, что, если использовать API Concat/Length/IsEmpty/etc., то разницы между включением и не-включением правой границы нет. Ну, во всяком случае, навскидку я ее не вижу.
Q>Вот мне недавно нужно было отформатировать кучу значений разных типов. И, чтобы не аллоцировать кучу строк, я форматировал всё в один общий массив char'ов. (В .NET Standard 2.1 для этого недавно появился API на Span'ах.) И размечен этот буфер аналогами ArraySegment, каждый внутри представлен парой (offset, count) с переходом в [start, end) при итерации. Q>И да, иногда некоторые значения — пустые строки, тогда их разметка — это пара (offset, 0) или [start, start) при итерации. Положение этого диапазона, хоть и пустого, в результирующем буфере не забывается, это тоже может использоваться.
Если я правильно понимаю, особой пользы от "обратных индексов" в данном примере нет.
Про полуоткрытый диапазон — опять же, если я правильно понимаю, указатели на подстроки в буфере идут с разрывами? Если бы было без разрывов, то одно из полей явно лишнее, достаточно было бы одного смещения, разве нет? А если с разрывами, то start при переходе определяется не просто предыдущим "offset + count", а более сложной формулой. А раз так, не вижу особой беды туда сунуть дополнительно +1, чтобы работать с закрытым диапазоном. Лично для меня так было бы понятнее. Кстати, я не понял, а как же захватывается последний символ буфера, он будет в последнем элементе указывать ЗА массив?
Здравствуйте, AlexRK, Вы писали:
ARK>Если я правильно понимаю, особой пользы от "обратных индексов" в данном примере нет.
Пользы от обратных индексов мне нет никакой, я их не использую. Речь ведь не про их пользу для меня, а про их консистентность, раз уж такая фича есть. Так вот, определение ^i как length — i консистентно с соглашением о полуоткрытых интервалах, а другой вариант неконсистентен. А соглашение о полуоткрытых интервалах само по себе важно, и непосредственно связано с нумерацией от нуля и избеганием «ошибок на единицу». Поэтому такой подход и распространён в современных языках, придуманных после Фортрана.
Если они вам тоже не нужны, добавьте в EditorConfig строчки:
ARK>Про полуоткрытый диапазон — опять же, если я правильно понимаю, указатели на подстроки в буфере идут с разрывами?
В этом примере да, кроме отформатированных объектов был ещё посторонний текст.
ARK>Если бы было без разрывов, то одно из полей явно лишнее, достаточно было бы одного смещения, разве нет?
Всё так, такое тоже было в моей практике. Например, один сплошной массив всех ребёр графа (сгруппированных и упорядоченных по source-вершине), и дополнительная разметка, какой поддиапазон этого массива какой вершине инцидентен. Там без разрывов, и exclusiveEnd одного диапазона совпадает с inclusiveStart следующего, поэтому просто смещения. Всё прекрасно стэкается друг с другом, ±1 нигде не фигурируют, пустые диапазоны (отсутствуют исходящие рёбра в некоторых вершинах) вполне естественно сохраняются как повторяющиеся start'ы. Для порождения энумератора по поддиапазону как раз удобно представление [start, end), а не (offset, count) как принято в API, чтоб избежать лишних сложений.
ARK>А если с разрывами, то start при переходе определяется не просто предыдущим "offset + count", а более сложной формулой.
В этом случае start при переходе определяется своим сохранённым offset, а не рассчитывается от offset'а предыдущего.
ARK>А раз так, не вижу особой беды туда сунуть дополнительно +1, чтобы работать с закрытым диапазоном.
Так +1 или -1? Это просто не нужно, это лишнее пространство для ошибок, не говоря уже про лишние вычисления. И отсутствие единообразия: если без разрывов, то используем «полуоткрытый» подход, а если с разрывами, то «закрытый» подход.
ARK>Кстати, я не понял, а как же захватывается последний символ буфера, он будет в последнем элементе указывать ЗА массив?
Не вижу проблемы. Например, строка s = "key: 610" длиной 8 символов:
key: 610
[ )
012345678
В ней подстрока 610 выкусывается диапазоном [5, 8), длина её 8 — 5 = 3 без ±1. Да, 8 здесь указывает на позицию вне массива, как и всегда в обращении array[length]. Проблем это не создаёт, потому что к элементу s[8] обращения нет, все индексы перебираются в асимметричных ограничениях 5 ≤ i < 8 без ±1.
Здравствуйте, Kolesiki, Вы писали: [-0]
Может вам и не очевидно, но народ в МС просто сделал по традиции всех (не могу даже вспомнить хоть один контрпример)
скриптовых ЯП
А в них, еще до рождения шипров, был стандарт: x[-1] — последний элемент списка/массива
Руби, Перл, "Наше автоматизация всё" Groovy(!), "наше ИИ всё" Python etc
А вы тут... развели категорическую бодягу.
Хотя нет, мир .NET упорно сопротивлялся этой весьма удобной фишке, в Powershell увы тоже нет.
Что не одобряю, так это испольвание уродской крыши вместо нормального, привычного отрицательного индекса