Ввод массивов заставил меня задуматься о синтаксисе. Итак, изначальная идея состоит в том, чтобы сделать синтаксис таким:
Object Method Parameter
Если метод возвращает значение, то оно кладётся на стек.
С методом get всё прекрасно. Мы можем вызывать его явно:
my_array get 11 // Положить на стек 12-й элемент массива my_array
Но с методом set всё сложнее. Мы должны иметь возможность указать программе, что мы хотим изменить 12-й элемент массива my_array.
Теоретически это можно было бы сделать так:
my_array set 11 = "zzz"
Или даже проще - вызывать метод set неявно:
my_array 11 = "zzz"
Но, что если 12-й элемент массива my_array - тоже массив, и мы хотим изменить в нём третий элемент? Получается конструкция вида:
my_array 11 3 = "ddd"
Вроде всё прекрасно, сейчас у меня именно так и сделано. Но мне пришла замечательная на первый взгляд идея - чтобы метод get массива мог возвращать массив данных, если в качестве индекса использовать массив с индексами.
my_array [ 1 2 [ 6 8 ] [ 5 3 ] 9 ]
Выглядит прекрасно. Эта команда возвратит массив с элементами массива my_array в следующем порядке:
[ 1 2 6 7 8 5 4 3 9 ]
Но неявный вызов приводит к тому, что например мы вводим массивы:
[ 1 2 3 ]
[ 4 5 6 ]
[ $$0 $$1 ]
Глядя на этот код можно подумать, что третья команда создаст массив
[ [ 1 2 3 ] [ 4 5 6 ] ]
Но это не так. Она эквивалента командам
[
$$0 get $$1
]
И тут я понимаю, что неявный вызов get делает программу трудночитаемой. Например, что если число 11 мы будем брать со стека?
my_array $0 3 = "ddd"
Цифра 3 задаёт 4-й элемент. Но четвёртый элемент в массиве $0 (кто знает, вдруг это массив?) или 4-й элемент в массиве my_array $0 ?
Получается так, что мы должны оставить перечисление элементов быть перечислением (как оно и выглядит в коде), взятие элемента по индексу снабдить явным синтаксисом - что-нибудь вроде:
{ { my_array } 11 } 3
Выглядит громоздко, но это вполне читаемо.
Возможно возникнет вопрос: зачем городить огород, если можно разложить эту конструкцию на последовательность операций вида:
my_array select 11
$0 select 3
$1 = "zzz"
И в принципе это выглядит более-менее читаемо и соответствует логике синтаксиса. Но этот способ заставляет нас перейти от синтаксиса читаемого к синтаксису ассемблерного типа, который читается намного хуже, а следовательно и ошибку в коде найти гораздо сложнее.
Второй недостаток - в том, что у нас появляется новый тип объекта - ссылка на элемент массива. $0 - это ссылка, $1 - это ссылка. Они кладутся на стек и там лежат, хотя изначально в этом нет необходимости.
Проблема элемента-ссылки на объект в массиве в том, что она может стать невалидной, если мы удалим этот элемент из массива. То есть это объект временного характера, и лучше всего ограничить его время существования пределами одной команды.
Поэтому синтаксис с фигурными скобками выглядит логичнее и читабельнее. Ведь мы можем использовать разные варианты в одной строке:
{ { my_array } $0 } $1 = "zzz"
{ my_array } { $0 } $1 = "ddd"
Но лично меня как-то удручают эти фигурные скобки. Хотя они позволяют использовать их для создания выборок:
{ my_array1 my_array2 my_array3 } 256
Это интересная возможность. Пожалуй я так и сделаю. Раз идей получше нет.
Но я подумал вот о чём. Конструкция вида
{ my_array } [ 11 ]
должна возвращать на стек массив, содержащий 12-й элемент массива my_array. А вот конструкция вида
{ { my_array } 11 } 3 = "zzz"
она должна работать с массивом на стеке? Как если бы
{ my_array } 11
{ $0 } 3 = "zzz"
Или она должна работать с 12-м элементом массива my_array, как с массивом?
Вот, что я вижу. Мы имеем оператор определения диапазона данных. А нам нужен оператор указания адреса в массиве. То есть это две разных операции.
Получается, что нужно писать код примерно так:
3 of { 11 of my_array }
[ 3 of $0 ] of my_array
Тогда получается понятно, что имеется в виду. Но парсить такого вида конструкции - в принципе ничего особо сложного в этом тоже нет.
И оператор задания выборки мне тоже нравится:
256 of { my_array1 my_array2 [ 1 2 3 ] of my_array3 }
Красота конечно, но мозг программиста вряд ли сможет понять, что имел в виду другой программист. Потребуется метод для просмотра подобных выборок.
Но я подумал вот о чём. Что, если мы захотим сделать выборку по условию? Например для всех элементов больше 100? Как это можно было бы задать?
Думаю, что логично сделать это конструкциями языка. Что-нибудь вроде:
for_each { my_array1 my_array2 } do
if $0 > 100 then
$0 = "zzz"
;
;
В данном случае на каждой итерации элемент $0 - это указатель на элемент выборки. То есть снова объект-ссылка, что нехорошо.
С другой стороны, объект-выборку проще всего представить как массив объектов-ссылок. И в принципе было бы довольно удобно иметь возможность расположить его на стеке, чтобы затем ссылаться на него. Но нужно непременно снабдить его средствами инвалидации, а так же предоставить программисту возможность проверять валидность.
В целом это выглядит довольно просто. Если невалиден один из элементов, то невалидной становится вся выборка. Тогда не нужно будет при доступе к каждому элементу проверять его персональную валидность.
Но я спросил себя вот о чём. Должна ли запись вида
[ [ 0 10] ] of my_array
создавать выборку, или выборка должна задаваться явно?
{ [ [ 0 10 ] ] of my_array }
Разница в том, что в первом случае мы можем копировать элементы, а во втором создавать массив-выборку. Ведь аналогичный синтаксис можно применять и для доступа к свойствам объектов:
x of my_point = 10
y of my_point = 20
Логично предположить, что в данном случае оператор of создаёт выборку, то есть указатель на объект-свойство. Это красиво выглядит и не нужно городить конструкцию из фигурных скобок. Но как тогда произвести копирование элементов из массива в массив на стеке?
Теоретически ничто не мешает использовать для этого метод get явным образом:
my_array get [ [ 0 10 ] ]
А для создания выборки оператор of:
[ [ 0 10 ] ] of my_array = "zzz"
Наверное я так и сделаю. Это выглядит читабельно и логика синтаксиса не нарушается. Да будет так.
Комментариев нет:
Отправить комментарий