Эргономика нотации

Mar 21, 2013 17:14

"Господи, соверши для Ла Гира то, что Ты хотел бы, чтобы Ла Гир совершил для Тебя, если бы Ты был Ла Гиром, а Ла Гир Господом." (c) Ла Гир


Некоторые личные впечатления по поводу эргономики нотации в .15926 Editor:

Возьмем пример на странице 57 документации:

show(type=part2.Scale, label=icontains("celsius"), hasDomain=groupby==check(label=icontains("capacity")))

returns those instances of Scale which have "celsius" in label and simultaneously have domain in property spaces with "capacity" in label. The results are returned grouped by domains.

Развертка этого кода, изложенная словесно, выглядит примерно так:

(1) "Получить из набора данных множество элементов, каждый из которых относятся к типу "Scale";
(2) выбрать из них те, в литеральном свойстве "label" которых имеется слово "celsius";
(3) далее выбрать из полученных те, у которых в роли hasDomain имеестся ссылка на элемент ("домен"),
(4) в литеральном свойстве "label" которого имеется слово "capacity";
(5) и, сгруппировав элементы по имени "домена",
(6) показать."

Если сопоставить позиции "атомарных операций" в тексте и в коде:

(6) show(
(1) type=part2.Scale,
(2) label=icontains("celsius"),
(3) hasDomain
(5) =groupby
(4) ==check(label=icontains("capacity")))

...можно наблюдать, что даже в довольно простом примере порядок изложения несколько нарушается.

Примерно аналогичная по результату (с поправкой на отличия в поведении groupby) псевдо-C#-кодная-флюент-цепочка выглядит более длинной, но за счет сохранения порядка изложения и некоторой избыточности описания "атомарной операции" остается примерно настолько же ясной:

(0) DATA_IN_STORE
(1) .Where ( el => el.type == part2.Scale )
(2) .Where ( el => el.label.Contains("celsius") )
(3) .Where ( el => el.hasDomain != null &&
(4) el.hasDomain.label.Contains("capacity") )
(5) .GroupBy ( el => el.hasDomain)
(6) .show();

Что можно констатировать на этом этапе:
1. питоновский код в-общем - работает;
2. он краткий, и его довольно просто написать.
3. его все еще возможно прочитать и понять, хотя, если не иметь текстовой подсказки, можно затратить время, сопоставимое, например, с тем, что было потрачено на осознание нюансов смысла "молитвы Ла Гира" из эпиграфа.

Следующий пример на той же странице:

show(type=part2.Classification,hasClassified=out==check(type=part2.PropertyQuantification), hasClassifier=groupby==check(type=part2.Scale))

will return all property quantification relationships grouped by instances of Scale that classify them.

Расщепленный "на атомы" выглядит так:

(9) show(
(1) type = part2.Classification,
(5) hasClassified
(6) =out
(7) ==check( type = part2.PropertyQuantification ),
(2) hasClassifier
(4? 8?) =groupby
(3) ==check( type = part2.Scale ) )

Из-за того что "порядок написания" уже в нескольких точках не соответвует "порядку исполнения", дешифровать его мне удалось исключительно благодаря наличию строчки с пояснением, потому как только из нее удалось понять, что же должно быть ее результатом. И то, нюанс с финальной группировкой остался не вполне проясненным:

(1) "Получить из набора данных множество элементов (X), каждый из которых относятся к типу "Classification";
(2) выбрать из полученных те, у которых в роли hasClassifier имеется ссылка на элемент,
(3) который является инстансом типа "Scale"
(4) ( сгруппировав их по имени этого элемента? или что? );
(5) из ссылок на элементы, которые содержатся в ролях hasClassified элементов из X
(6) получить другое множество элементов (Y);
(7) выбрать из элементов множества Y те, которые относятся к типу "PropertyQuantification"
(8) и сгруппированными ( каким же путем сюда проникло группирование из предыдущего этапа ? )
(9) показать их."

Псевдо-флюент-запись, в которой порядок изложения сохранен, читается не многим хуже, чем предыдущий пример ( out-параметру здесь соотвествует Select ) :

(0) DATA_IN_STORE
(1) .Where ( el => el.type == part2.Classification )
(2) .Where ( el => el.hasClassifier != null &&
(3) el.hasClassifier.type == part2.Scale )
(5) .Where ( el => el.hasClassified != null )
(6) .Select ( el => el.hasClassified )
(7) .Where ( el => el.type == part2.PropertyQuantification )
(8) .GroupBy ( el => el.hasClassifier.name )
(9) .show();

Резюме по личным впечатлениям:
При нарушении порядка изложения в чуть более сложных примерах за счет "комбинаторного взрыва" в мозгу происходит перегрузка механизма кратковременной памяти. И соответсвенно теряется возможность быстро понимать написанное.

Причина по которой применен такой синтаксис, в целом понятна : Питон флюент-интерфейсы "может", но не "любит", потому как "атомарность операций" ведет к дополнительным потерям производительности. Тем не менее, задача как-то дополнительно управлять порядком исполнения не снимается - просто из "видимой части айсберга" основная работа вымещаются в "притопленную". В частности из-за этого появляется необходимость в функции check. Хотя понятно что find, show и check - это на самом деле частные случаи одной и той же функции ( ядром которой является аналог Where в C#-коде ) с прикрученными побочными задачами и дополнительными наложенными ограничениями. К примеру find не имеет делать groupby, check должен вызываться лишь изнутри других выражений, show c groupby имеет несколько другой видимый результат, чем show без groupby, out может использоваться не более одного раза на уровне и т.п. Обилие сочетаний частных случаев с другими частными случаями требует примеров и ведет к распуханию документации.

В целом нельзя сказать что это "не работает". Но зарождается подозрение, что при дальнейшем неминуемом расширении возможностей - методика работы будет напоминать пресловутую "куклу вуду и иголки". Чего бы очень не хотелось...
Previous post Next post
Up