Итак, предположим что Вы причастны к разработке нового императивного ЯП(возможно он позиционируется как "С++ killer" (Да, сильно, а что делать )). Какими на Ваш взгляд должны бы быть встроенные в язык массивы? (А может и не надо "встроенности"? (std::array))
Предпологается что язык статически типизирован(как Вы это понимаете) и имеет некоторый встроенный набор базовых типов. Кроме того, предположим, что ссылок и указателей на данном этапе нет(но они могут появиться, исходя из Ваших предположений и пожеланий).
Итак(да/нет/мысли):
1. Массив как встроееный тип.
2. Массив как агрегат (а'ля С++).
3. Непрерывное размещение элементов массива в памяти.
4. Совместимость с C++ (see 3)
5. Массивы N-го порядка как массив из массиво N-1 порядка.
6. Непрерывная область памяти + encode lambda expression.
7. Прямоугольные/jagged/sparse arrays
8. ?
9. синтаксис
10. и в некотором сысле семантика...
+
11. Вопросы оптимизации
12. возврат\передача by value (в т.ч. массивов с неизвестным размером)
13. splice's
14. способы итерации
15. любые мысли
Интересут все(на данном этапе ФЯ идут боком; да и массивы в ИЯ ортогональны), так как многие источники по language design умалчивают этот вопрос, либо довольствуются известными конструкцимя.
Проверка выхода за границы особо не интересут (ибо сделать ее не составляет труда).
Здравствуйте, Lande, Вы писали:
L>Вопрос к RSDN All:
L>Итак, предположим что Вы причастны к разработке нового императивного ЯП(возможно он позиционируется как "С++ killer" (Да, сильно, а что делать )). Какими на Ваш взгляд должны бы быть встроенные в язык массивы? (А может и не надо "встроенности"? (std::array))
Здравствуйте, Lande, Вы писали:
L>Здравствуйте, FR, Вы писали:
FR>>Предлагаю посмотреть на D и python.
L>Я уже столько всего пересмотрел..
L>+ L>
L>...либо довольствуются известными конструкцимя.
А ты что ищешь неизвестное или самое удобное?
Если второе то по моему в D это уже реализованно, если еще добавить туда несколько вкусных штук из питона 2.4 (отрицательные индексы, разворот массивов и т. п.) то будет близко к идеалу.
Здравствуйте, Lande, Вы писали:
L>Итак, предположим что Вы причастны к разработке нового императивного ЯП(возможно он позиционируется как "С++ killer" (Да, сильно, а что делать )). Какими на Ваш взгляд должны бы быть встроенные в язык массивы? (А может и не надо "встроенности"? (std::array))
matlab
L>Итак(да/нет/мысли):
L>1. Массив как встроееный тип.
да
L>2. Массив как агрегат (а'ля С++).
да
L>3. Непрерывное размещение элементов массива в памяти. L>4. Совместимость с C++ (see 3) L>5. Массивы N-го порядка как массив из массиво N-1 порядка. L>6. Непрерывная область памяти + encode lambda expression. L>7. Прямоугольные/jagged/sparse arrays
да. это накладывает ограничения на пункты 1-6
L>8. ? L>9. синтаксис L>10. и в некотором сысле семантика...
matlab
L>+ L>11. Вопросы оптимизации
да
L>12. возврат\передача by value (в т.ч. массивов с неизвестным размером)
Здравствуйте, Lande, Вы писали:
L>Вопрос к RSDN All:
L>Итак, предположим что Вы причастны к разработке нового императивного ЯП(возможно он позиционируется как "С++ killer" (Да, сильно, а что делать )). Какими на Ваш взгляд должны бы быть встроенные в язык массивы? (А может и не надо "встроенности"? (std::array))
А кроме синтаксических улучшений, что еще в языке предполагается?
Здравствуйте, Lande, Вы писали:
L>Вопрос к RSDN All:
L>Итак, предположим что Вы причастны к разработке нового императивного ЯП(возможно он позиционируется как "С++ killer" (Да, сильно, а что делать )). Какими на Ваш взгляд должны бы быть встроенные в язык массивы? (А может и не надо "встроенности"? (std::array))
Такое соображение: одномерный массив — это отображение (оно же мэппинг, оно же hash) числа на значение. Соответственно, двумерный массив — это отображение пары чисел (что такое пара чисел? а это ведь тоже массив!) на значение.
Посмотрим, хорошо ли hash держит типичные массивные операции:
Взять значение по индексу — идеально.
Положить значение — фантастически (т.е. мы даже за границы массива никогда не сможем выпрыгнуть).
Перебор значений — даже лучше, чем в классике (если в синтаксис добавить оператор ForEach), т.к., во-первых, в разреженном массиве не нужно анализировать пустоты, а во-вторых, оператор ForEach может служить синтаксической основой параллелизма. Единственная проблема — ForEach должен возвращать пару (индекс, значение).
Определение количества элементов — тут тоже всё ОК.
Определение границ — из рук вон плохо. Но я, например, не припоминаю, когда и зачем мне такая фича была нужна. К тому же, что есть граница у многомерного массива?
Добавление в хвост — тоже плохо, т.к. нужно знать верхнюю границу. Но эту проблему можно обходить разными способами в зависимости от контекста.
Удаление значения — без проблем, если не забивать голову сдвигом хвоста на освободившееся место.
Единственный минус этого подхода: hash — это более тормозная штука, нежели непрерывный массив в памяти. Но, господа, программы тормозят не из-за скорости базовых операций, а из-за неоптимальности алгоритмов, и по этой причине разгрузка головы программера от борьбы с границами массивов может привести к тому, что в результате программа будет работать быстрее!
Впрочем, ограниченные непрерывные массивы тоже можно оставить как подвид для работы, например, с битмэпами.
(да/нет/мысли): L>1. Массив как встроееный тип.
Да, хотя и не обязательно. L>2. Массив как агрегат (а'ля С++).
Да. L>3. Непрерывное размещение элементов массива в памяти.
Уже сказал. L>4. Совместимость с C++ (see 3)
Для ковыряния в памяти можно сделать какую-нибудь штуку типа BINARY. L>5. Массивы N-го порядка как массив из массиво N-1 порядка.
Это точно никуда не годится! В системах, где так сделано, массвами порядка больше 1 вообще нельзя пользоваться!
Кстати, hash снимает проблему многомерности легко и наиболее естественно.
Здравствуйте, Voblin, Вы писали:
V>Взять значение по индексу — идеально.
Это классическая то хеш-таблица? Ничего не путаешь?
V>Перебор значений — даже лучше, чем в классике (если в синтаксис добавить оператор ForEach), т.к., во-первых, в разреженном массиве не нужно анализировать пустоты, а во-вторых, оператор ForEach может служить синтаксической основой параллелизма. Единственная проблема — ForEach должен возвращать пару (индекс, значение).
А как быть с сохранением порядка?
V>Определение границ — из рук вон плохо. Но я, например, не припоминаю, когда и зачем мне такая фича была нужна. К тому же, что есть граница у многомерного массива?
А что такое определение границ?
V>Удаление значения — без проблем, если не забивать голову сдвигом хвоста на освободившееся место.
А забивать не надо, если мы претендуем на универсальность. А еще вопрос качественного хеш-кода тоде не так прост. А еще в хеше нельзя хранить повторяющиеся ключи.
... << RSDN@Home 1.2.0 alpha rev. 646 on Windows XP 5.1.2600.131072>>
Здравствуйте, Lande, Вы писали:
L>Итак, предположим что Вы причастны к разработке нового императивного ЯП(возможно он позиционируется как "С++ killer" (Да, сильно, а что делать )). Какими на Ваш взгляд должны бы быть встроенные в язык массивы? (А может и не надо "встроенности"? (std::array))
L>1. Массив как встроееный тип.
Пригодится.
L>2. Массив как агрегат (а'ля С++).
Я бы даже сказал — а-ля Си.
L>3. Непрерывное размещение элементов массива в памяти.
Пункты 2 и 3 пригодятся, если этот язык — действительно C++killer. То есть предполагает работу с низким уровнем (в том числе).
Может быть, желательно разнести POD-массивы (непрерывные, с агрегатной инициализацией) и высокоуровневые коллекции (абстрагированные от вопросов размещения).
Хотя агрегаты — сами по себе вещь приятная.
В С++ невозможно подставлять в выражения массивы-литералы (за исключением строк). А иногда хочется... вот и изобретают велосипеды по конструированию коллекций через бинарные операторы.
L>4. Совместимость с C++ (see 3)
Джентельменский минимум — совместимость с Си по POD-структурам и совместимость с COM по формату виртуальных вызовов.
Возможно, что COM-интерфейсы можно специальным образом помечать, чтобы компилятор знал: здесь — нужна совместимость, а в остальных случаях выбирал механизм виртуальных вызовов по своему усмотрению.
L>5. Массивы N-го порядка как массив из массиво N-1 порядка.
Только в паре с одноместным оператором []. В этом случае декомпозиция массива на подмассивы вытекает из строгой типизации.
Если же оператор[] может иметь произвольную арность — то можно трактовать такие массивы как гипер-прямоугольники.
Интересный подход к многомерным массивам в языке PL/I; там можно делать срезы по произвольному индексу, а не только по первому, как в С/С++.
L>6. Непрерывная область памяти + encode lambda expression.
То есть?
L>7. Прямоугольные/jagged/sparse arrays
jagged — это как раз массивы массивов (переменного размера).
Неплохо бы ввести два класса
— многомерные массивы (гиперпрямоугольники), в том числе разреженные
— иерархические (jagged)
Разница в том, что у первых можно делать срезы по произвольному индексу. Плюс всякие фишки с перестановкой размерностей(транспонирование).
L>8. ? L>9. синтаксис L>10. и в некотором сысле семантика... L>+ L>11. Вопросы оптимизации L>12. возврат\передача by value (в т.ч. массивов с неизвестным размером)
Больно дорогое это удовольствие — передавать по значению. Нужен механизм CopyOnWrite.
Вот, кстати, если бы COW вошёл в базис языка (как вошёл GC), это был бы плюс.
L>13. splice's L>14. способы итерации
Без разницы. Минимум, что нужно — произвольный доступ по индексу.
Даже не требуется вводить адресную арифметику на уровне языка — просто пишем обёртки-итераторы произвольного доступа, над которыми определяем адресную арифметику.
Так что любители работы с полуинтервалами в стиле STL не почувствуют ущерба.
Стоит разработать исчисление диапазонов (в т.ч. многомерных). Тогда foreach станет гармоничным. Чтобы можно было не только извлекать элементы, но и находить поддиапазоны.
L>15. любые мысли
Здравствуйте, Lande, Вы писали:
L>1. Массив как встроееный тип.
Нет
L>2. Массив как агрегат (а'ля С++).
Да
L>3. Непрерывное размещение элементов массива в памяти.
Скорее параметризовать массив типом менеджера памяти. Пусть он думает как расположены элементы и как получить i-й. Кстати при таком подходе разницы между массивом и списком уже не будет.
Ещё тогда можно делать разрежённые массивы, то есть получить массив всех чётных элементов без перераспределения памяти.
L>4. Совместимость с C++ (see 3)
Да, надо.
L>5. Массивы N-го порядка как массив из массиво N-1 порядка.
Спорно. Производительность пострадает. А если сделать управление памятью какое-нибудь и учеть пожелания пункта №3 то можно получать срез по любому индексу.
L>9. синтаксис
Предлагаю оператор индексации — [] и и итераторы .
L>Интересут все(на данном этапе ФЯ идут боком; да и массивы в ИЯ ортогональны), так как многие источники по language design умалчивают этот вопрос, либо довольствуются известными конструкцимя.
Я бы обощил всё что только можно. Например добавил опциональную возможность следить за изменениями элементов массива.
Здравствуйте, AndrewVK, Вы писали:
V>>Взять значение по индексу — идеально.
AVK>Это классическая то хеш-таблица? Ничего не путаешь?
Имеется в виду ключ, т.е. операции
Arr[i]
и
HashTable.Get(i)
совершенно эквивалентны
V>>Перебор значений — даже лучше, чем в классике (если в синтаксис добавить оператор ForEach), т.к., во-первых, в разреженном массиве не нужно анализировать пустоты, а во-вторых, оператор ForEach может служить синтаксической основой параллелизма. Единственная проблема — ForEach должен возвращать пару (индекс, значение).
AVK>А как быть с сохранением порядка?
Да уж, с этим проблема... ForEach — это действительно беспорядочная штука. Видимо, решение сдесь только одно — сделать упорядоченную выборку функцией такого "массива"
V>>Определение границ — из рук вон плохо. Но я, например, не припоминаю, когда и зачем мне такая фича была нужна. К тому же, что есть граница у многомерного массива?
AVK>А что такое определение границ?
Узнать максимальный индекс.
V>>Удаление значения — без проблем, если не забивать голову сдвигом хвоста на освободившееся место.
AVK>А забивать не надо, если мы претендуем на универсальность. А еще вопрос качественного хеш-кода тоде не так прост. А еще в хеше нельзя хранить повторяющиеся ключи.
В массиве, в общем, тоже два значения в одну ячейку не запихаешь.
Здравствуйте, AndrewVK, Вы писали:
V>>Узнать максимальный индекс.
AVK>И в чем проблема?
Тоже думаю, что ни в чём. Если массив в принципе не имеет ни верхней, ни нижней границы, то, соответственно, от него никак не получится добиться "Память не может быть Read" и, следовательно, отпадает необходимость ежесекундной проверки индекса на попадание в границы.
Здравствуйте, adontz, Вы писали:
L>>3. Непрерывное размещение элементов массива в памяти.
A>Скорее параметризовать массив типом менеджера памяти. Пусть он думает как расположены элементы и как получить i-й. Кстати при таком подходе разницы между массивом и списком уже не будет.
По скорости работы еще как будет.
A>Ещё тогда можно делать разрежённые массивы, то есть получить массив всех чётных элементов без перераспределения памяти.
L>>5. Массивы N-го порядка как массив из массиво N-1 порядка.
A>Спорно. Производительность пострадает.
Хм... А тебе не кажется, что в С массивы именно так и сделаны ? Нет ведь там многомерных массивов. Нет вообще. Двумерный массив есть массив из одномерных массивов. И никакая производительность не падает.
A>Предлагаю оператор индексации — [] и и итераторы .
ИМХО должно быть 2 типа
1. Массив в стиле С/C++. Т.е. пункт 3 — непрерывное размещение. Под этим также понимаю (пусть условно) массивы указателей на массивы и т.п. Для максимально высокого быстродействия. Что там ни говорите, а лучше, чем в С/C++ никто ничего не придумали и не придумает.
2. Обобщенный массив. Некий класс с перегрузкой operator[], итераторами и менеджером памяти. Для реализации всех и всяческих хитрых затей типа массива с четными только индексами, с хранением данных в Интернете и доступом через XML и т.п.
Кстати, в том же C# я бы добавил value-массив из value типов. Почему-то можно описать структуру или просто int, а вот массив структур или int — это уже класс с хранением в куче. Т.е.
int a0,a1,a2,a3,a4,... a99;
можно, и все в стеке
а вот
int a[100];
это уже System.Array и место ему в куче. Нелогично ИМХО.
Здравствуйте, Pavel Dvorkin, Вы писали: PD>Кстати, в том же C# я бы добавил value-массив из value типов. Почему-то можно описать структуру или просто int, а вот массив структур или int — это уже класс с хранением в куче. Т.е.
PD>int a0,a1,a2,a3,a4,... a99;
PD>можно, и все в стеке
PD>а вот
PD>int a[100];
PD>это уже System.Array и место ему в куче. Нелогично ИМХО.
Зато можно
private struct IntBuffer
{
private fixed int a[100];
public int this[int index]
{
get { return a[index];}
set { a[index]=value; }
}
}
public void Test()
{
unsafe
{
IntBuffer buffer = new IntBuffer();
for(int i =0;i<100;i++)
buffer[i] = 2*i;
}
}
1.1.4 stable rev. 510
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Насколько я понимаю, это все же класс System.Array. В хипе он, а не в стеке. А хотелось бы все же в стеке. Да и без unsafe тоже бы не помешало.
ИМХО здесь именно тот момент, когда идеология, будучи последовательно примененной, вынуждает жертвовать здравым смыслом.
Кстати, есть и другой пример — когда идеологией пожертвовали в пользу здравого смысла. Я имею в виду string. Класс, но ведет себя порой как value — сравнение, инициализация.
Здравствуйте, Pavel Dvorkin, Вы писали:
A>>Скорее параметризовать массив типом менеджера памяти. Пусть он думает как расположены элементы и как получить i-й. Кстати при таком подходе разницы между массивом и списком уже не будет. PD>По скорости работы еще как будет.
В смысле не придётся создавать две совсем разные сущности. Вся разница уместиться в менеджер памяти.
A>>Спорно. Производительность пострадает. PD>Хм... А тебе не кажется, что в С массивы именно так и сделаны ? Нет ведь там многомерных массивов. Нет вообще. Двумерный массив есть массив из одномерных массивов. И никакая производительность не падает.
adontz wrote:
> A>>Скорее параметризовать массив типом менеджера памяти. Пусть он думает > как расположены элементы и как получить i-й. Кстати при таком подходе > разницы между массивом и списком уже не будет. > PD>По скорости работы еще как будет. > В смысле не придётся создавать две совсем разные сущности. Вся разница > уместиться в менеджер памяти.
С алгоритмической точки зрения std::vector (массив) и std::list (список) очень разные вещи. И не в менеджере памяти дело.
Или ты под массивом и списком понимаешь что-то другое?
> A>>Спорно. Производительность пострадает. > PD>Хм... А тебе не кажется, что в С массивы именно так и сделаны ? Нет > ведь там многомерных массивов. Нет вообще. Двумерный массив есть массив > из одномерных массивов. И никакая производительность не падает. > > А вот давай заглянем сюда — http://www.rsdn.ru/article/alg/2darray.xml
Но это сам язык не поддерживает, нельзя написать a[i,j,k], сравни с тем же паскалем. Поэтому и не делали встроенной
поддержки, т.к. легко можно сделать при необходимости.
Posted via RSDN NNTP Server 2.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, kan_izh, Вы писали:
_>С алгоритмической точки зрения std::vector (массив) и std::list (список) очень разные вещи. И не в менеджере памяти дело. _>Или ты под массивом и списком понимаешь что-то другое?
Да разные, но внешне вполне одинаковые.
На самом деле я каждый день крою создателей STL матом, потому что vector и list это УЖОС! Надо было list и linked_list! Сколько новичков прочтя в условии про список элементов писали std::list хотя там больше подходит std::vector. А сколько математиков пытались перемножить два std::vector?
_>Но это сам язык не поддерживает, нельзя написать a[i,j,k], сравни с тем же паскалем. Поэтому и не делали встроенной _>поддержки, т.к. легко можно сделать при необходимости.