Re[33]: Языки общего назначения не имеют смысла!
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 16.04.12 16:40
Оценка: :)
Здравствуйте, WolfHound, Вы писали:

WH>Честно говоря, я не понял, зачем была выбрана модель персистентных объектов?

WH>Чем она такая хорошая?

Например на ней легко делать рекурсивные запросы любой глубины и сложности. На реляционной надо сначала приседать с запросом, потом приседать с перформансом запроса.
Re[34]: Языки общего назначения не имеют смысла!
От: WolfHound  
Дата: 16.04.12 16:54
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Например на ней легко делать рекурсивные запросы любой глубины и сложности.

I>На реляционной надо сначала приседать с запросом,
Это зависит от языка.

I>потом приседать с перформансом запроса.

А в объектной модели, которая маппится на реляционную БД все будет просто летать?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[12]: Языки общего назначения не имеют смысла!
От: PSV100  
Дата: 16.04.12 17:01
Оценка:
Здравствуйте, alex_public, Вы писали:

PSV>Нужно и удобное прямое алгоритмическое программирование GUI. Какое бы не было крутое декларативное описание, но всех потребностей оно никогда не покроет. Здесь какой-нибудь miglayout очень кстати (соответственно и декларативный DSL должен иметь как бы прямую связь с API языка программирования, т.е. в DSL задаются те же элементы, что и в этом miglayout).


_>Точно. Вот его и ищем, но пока не видно ничего. Точнее есть нормальные решения в рамках системного языка, но хотелось бы всё же вынести это их него.


IUP (вики) — фреймворк для Lua (можно работать и из С) для GUI, кроссплатформенный, использует нативные контролы платформы. Есть и свой DSL (простые текстовые файлы) для задания GUI, но это, прежде всего, Lua (есть и соответствующее API из коробки), где можно вытворять чего хочешь: любой свой DSL, можно взять MetaLua, MoonScript и т.д.
Слабо заметен на фоне Qt, Wx, FoxToolkit, FLTK и пр., но, имхо, им неплохая альтернатива для ряда задач. Лично сам не юзал, но в своё время глаз на него положил.
Re[28]: Языки общего назначения не имеют смысла!
От: vdimas Россия  
Дата: 16.04.12 17:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

V>>Если я доверяю кусок кода непрофессионалу-бухгалтеру, то плохо, ес-но, т.к. он может банально всё уронить.

S>Не может, если хост языка ему не позволяет.

Ну ты же спросил насчет случая, когда язык приобретает св-ва языка общего назначения через подключение произвольных либ, так? В это случае может, ес-но, через неправильное использование этих самых библиотек, которые не обязательно безопасны, если мы договорились, что они произвольные.

V>>Опять сорри за ликбез, но нет. CRT является частью языка и стандарта, позволяя писать практически что угодно без линкера.

S>Я боюсь, что у вас ничего не получится без линкера.

На gcc, icc и многих других компиляторах получится. Причем, зависимости от CRT указывать не надо, в отличие от зависимостей от других либ, бо стандартные ф-ии обязаны работать "изкаробки". Я уже обращал внимание на то, что если другие либы надо указывать в параметрах компилятора или линкера для включения, то относительно CRT опции чуть другие по характеру — это опции отключения CRT или выбора типа CRT.


V>>Насчет твоих inp/outp. Если интересовался, то в защищенном режиме x86 порты отображены на карту виртуальной памяти. Во многих embedded-архитектрах, например PIC — точно так же без всякого защищенного режима — порты ввода-вывода лежат по специальным адресам. Но это фигня, дело-то не в порта, так? А в выполнении произвольной инструкции процессора, правильно? С/С++ чуть ли не единственные языки, где можно записать данные в некоторую область памяти (в сегмент данных, например) и передать туда управление. Так работают всякие нейтивные вирусы, писанные на С.

S>И это не имеет никакого отношения к импорту библиотек.

Это имеет отношение к твоему утверждению, что С/С++ так же подойдет на роль DSL. Не подойдет, т.к. нет каких-либо ср-в ограничить исходный код.

V>>В каком месте мы в этом убедились? На примере С/С++ никак не убедились, т.к. совокупность всех возможностей языка позволяет ему ставить раком произвольную аппаратную платформу.

S>Мне нравится ваша способность начисто игнорировать весь ход обсуждения. Что мы имеем? Пример С показывает, что для постановки раком платформы библиотеки ему не нужны, да и нет в языке ничего специального про библиотеки.

Я не игнорирую, я вижу что ты успел забыть на какие твои вопросы я даю ответы. Ты сделал кое-какие утверждения относительно С? Я не согласился и объяснил — почему. Потому что изкаробки слишком много возможностей, даже без внешних библиотек — из-за CRT и адресной арифметики ф-ий.


S>Пример "улучшенного Лого" показывает, что добавление библиотек никак не помогает поставить раком платформу. Но вас это не смущает.


Мы недообсуждали Лого, чтобы делать такие выводы. Я еще не увидел твоего примера целиком. Покажи предположительный синтаксис вызова произвольных внешних ф-ий для "расширенного Лого", а затем я тебе дам небольшой список экспорта, например, NT.DLL, с помощью которого можно уронить любую, самую защищенную программную среду.


V>>Да и взять сами термины: на мой взгляд specific area отличается от general area границами и более ничем. Поэтому для меня императивный DSL — это в первую очередь ограничение области приложения, а затем уже хелперы и прочие плюшки. Например, с точностью до тонкостей синтаксиса можно этот HTML-DOM обрабатывать из какого-нить C# или С++ при подключенной соответствующей библиотеке.

S>Совершенно верно. Поэтому изо всех языков, работающих с DOM, DSL-ями являются только CSS и XSLT. JS, как и С и C++, это типичный GPPL.

Опять по кругу... Если бы C/C++ не обладали CRT/CppRT, идущими как часть стандарта, и не имели адресной арифметики ф-ий, позволяющей передать управление куда угодно, я бы согласился. А так — нет.
Re[14]: Языки общего назначения не имеют смысла!
От: vdimas Россия  
Дата: 16.04.12 17:33
Оценка:
Здравствуйте, AndrewVK, Вы писали:

O>>Посмотрите на выпускников ВУЗов — они ни черта вообще не умеют


AVK>Выпускники, они разные бывают. Несколько человек на поток обычно вполне вменяемые. А остальные просто для корочки 5-6 лет отсидели, что то по ним мерять неинтересно.


Это да, но знакомые преподы говорят, что % вменяемых выпускников IT резко уменьшился за последние 10 лет. Сейчас их порядка по 1-2 на группу выходит из нашего ВУЗа, в 90-е выходило от четверти до трети и даже девушки что-то умели, что сейчас большая редкость.
Re[33]: Языки общего назначения не имеют смысла!
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.04.12 17:58
Оценка:
Здравствуйте, WolfHound, Вы писали:

AVK>>ООБД слишком неопределенный термин.

WH>Ты оперируешь персистентными объектами.

Не я, но в приведенном куске кода — да.

WH>>>У каждого объекта есть свой GUID используемый в качестве первичного ключа.

AVK>>Это неважно, что у него в качестве первичного ключа. Главное что он есть.
WH>Важно.

Почему?

WH>>>Версия. Как я понял сколько раз меняли объект. Хранятся ли предыдущие версии объекта?

AVK>>Нет.
WH>Что нет?

Не хранятся.

AVK>>Неважно. В примере это не используется.

WH>Важно. Как проектировать ДСЛ если не ясно что в системе твориться?

Как проектировать SQL, если неясно как работают функции lo_ххх в Postgres?

AVK>>Первые атрибуты описываются доменами и хранят непосредственно значение. ВТорые — ссылки на другие экземпляры объектов.

WH>Не понимаю. Зачем их разделять?

Набор данных, описывающих их, разный.

WH>>>bool IsPersistent а что объекты бывают не persistent? Зачем?

AVK>>Неважно. В примере нет неперсистентных объектов.
WH>Ох.

Можешь считать, что их вообще не существует, если тебе так комфортно. Ты же понимаешь, что мне не нужно конкретное готовое решение? Мне нужна демонстрация преимуществ подхода в целом.

WH>>>Ну и главный вопрос: Почему ООБД? ИМХО в БД должны быть только данные, а не методы итп.

AVK>>А в БД никаких методов и нет.
WH>Ессно нет. Она же у тебя реляционная. Или как?

Реляционная.

WH>Честно говоря, я не понял, зачем была выбрана модель персистентных объектов?


Это другая тема. Обработки, не связанные с агрегацией, редактирование конкретных экземпляров — все это удобнее и, главное, проще выражать в ОО форме. Там, где удобнее реляционная модель — можно писать реляционные запросы. Но запросы уже и так DSL. А вот для такого обрабатывающего кода — все далеко не так очевидно.

WH>Еще вопрос: Нужна ли распределенная работа?


В каком смысле распределенная? Распределенные сервера не нужны, а система в целом — конечно распределенная. Времена однопользовательских ERP давным давно прошли.
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[15]: Языки общего назначения не имеют смысла!
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.04.12 18:00
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Это да, но знакомые преподы говорят, что % вменяемых выпускников IT резко уменьшился за последние 10 лет.


Это, в основном, потому что профессия стала престижнее.
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[24]: Языки общего назначения не имеют смысла!
От: vdimas Россия  
Дата: 16.04.12 18:05
Оценка:
Здравствуйте, AndrewVK, Вы писали:

V>>Грамматика SQL проста до безобразия

AVK>Я бы так не сказал. Там местами даже в LL(k) не укладывается, LL(*) нужен.

Зато прекрасно справляется параллельный LR(1), т.к. всегда может отличить конец одного выражения от начала другого без этих разделителей (все копии автомата "схлопываются" в этом месте к 1-й). Или его минимизированный вариант — LALR. И вообще, любые параллельные парсеры для этого дела подойдут, например Эрли.

Под простотой грамматики я имел ввиду малое кол-во правил для описания обсуждаемого оператора SELECT, т.е. можно закодить LR(1) врукопашную по системе правил — это будет вполне обозримый объем работ на несколько вечеров. (Для перфекционистов, выбирающих LALR, лучше использовать готовый генератор, ес-но, чтобы не налепить ручных ошибок).


V>> и в сети лежит множество готовых парсеров, которые расширить на свои потребности можно с пол-пинка.

AVK>Парсер это примерно 5% потребной работы, если не меньше.

Именно что. Но ведь самый популярный контраргумент против разработки самописных DSL — якобы сложность разработки парсера.

На самом деле, остальные 95% — они тоже не с 0-ля будут писаны в реальной разработке. К тому моменту, когда созрели до DSL, обычно уже есть много из готовой инфраструктуры и понимания происходящего, которое теперь надо "просто чуть по-другому оформить".
Re[25]: Языки общего назначения не имеют смысла!
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.04.12 18:34
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Зато прекрасно справляется параллельный LR(1)


Не справляется. Там есть места, парсить которые можно только с откатами, за фиксированное число лексем определить нужное правило нельзя. К примеру, IN предикат бывает двух типов — когда в скобках список выражений и когда подзапрос. Т.е. может быть такое:
WHERE x IN (SELECT * FROM ys)
...
WHERE x IN (SELECT COUNT(*) FROM ys, SELECT COUNT(*) FROM zs)

Это две разных синтаксических конструкции, одна "IN" "(" <value_list> ")", другая "IN" <subquery>, но отличить их парсер, могущий заглядывать на фиксированное количество лексем, в точке перед скобкой не может в принципе. Нужно заглядывать вперед по правилу с subquery, и только если не получилось его отматчить, идти по ветке value_list. Т.е. нужны откаты.
И таких вещей несколько штук даже в sql'92 есть.

V>И вообще, любые параллельные парсеры для этого дела подойдут, например Эрли.


Ты под параллельными понимаешь парсеры с откатами (параллельным разбором правил) что ли? Тогда LL(k) или LR(k) такие парсеры называть некорректно.

V>Под простотой грамматики я имел ввиду малое кол-во правил для описания обсуждаемого оператора SELECT


В SQL'92, емнип, больше 6 сотен только для селекта. У меня, когда я выкинул все гавно типа указания кодировок и устаревших форм различных операторов, все равно больше сотни получилось.
Но, на самом деле, парсер это фигня, мизерная часть от общего объема транслятора. Один ресолвер типов по трудоемкости в разы больше.

V>, т.е. можно закодить LR(1) врукопашную по системе правил — это будет вполне обозримый объем работ на несколько вечеров.


С учетом построения нормального AST и промышленного качества кода, я бы сказал пару недель. У опытного человека. Ну и LR в такой ситуации не лучший выбор — диагностика ошибок, понимаешь ли.

V>Именно что. Но ведь самый популярный контраргумент против разработки самописных DSL — якобы сложность разработки парсера.


Не знаю у кого он популярный. Наверное у тех, кто периодически озвучивает тут очередную гениальную идею по хранению исходников в виде отпарcенного AST.

V>На самом деле, остальные 95% — они тоже не с 0-ля будут писаны в реальной разработке. К тому моменту, когда созрели до DSL, обычно уже есть много из готовой инфраструктуры и понимания происходящего, которое теперь надо "просто чуть по-другому оформить".


Ну, у меня такой проект до первого рабочего прототипа занял примерно 6 человекомесяцев. Потом еще пару пришлось потратить на переделку мест, где я сам же и схалтурил. Ну и еще месяца 4 в сумме ушло на докручивание нового функционала, в основном не мной.
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[24]: Языки общего назначения не имеют смысла!
От: koodeer  
Дата: 16.04.12 18:41
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>Это даже не смешно. При чем тут бизнесмен? Речь о специалисте по созданию DSL.


Да при том! Представим, что компьютеров нет. Совсем нет, не изобрели ещё! Ведь бизнесмены и без них смогут общаться между собой, именно на языке своего бизнеса, своими терминами. Так и было до компьютеризации. А потом пришли мы, программисты, и стали требовать, чтобы свою специфику бизнесмены выразили нам в терминах языков программирования. Мы не понимаем их, они нас.


K>>Это не я должен показывать. Это должны показывать бизнесмены.


AVK>Забудь, это фантастика. Заказчики не способны даже логически непротиворечиво изложить требования.


Странно, большинство моих заказчиков вполне адекватно излагают требования. Но на своём языке. Да, эти требования не перекладываются напрямую на программный код. Но это уже не проблемы их логики. Это проблемы отсутствия софта по созданию DSL.



Повторюсь, что хочу слишком многого. Я это понимаю.
Ещё понятнее донести свои мысли не могу. На сём предлагаю прекратить обсуждение.
Re[25]: Языки общего назначения не имеют смысла!
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.04.12 18:46
Оценка:
Здравствуйте, koodeer, Вы писали:

K>Да при том! Представим, что компьютеров нет. Совсем нет, не изобрели ещё! Ведь бизнесмены и без них смогут общаться между собой, именно на языке своего бизнеса, своими терминами.


Только такой язык невозможно будет реализовать. Умение формализовать естественно произошедшие вещи — важное и сложное умение. Собственно, все эти ООП, ФП, DSL — это все как раз про это.

AVK>>Забудь, это фантастика. Заказчики не способны даже логически непротиворечиво изложить требования.

K>Странно, большинство моих заказчиков вполне адекватно излагают требования.

Значит тебе повезло. Или специфика области, в которой ты работаешь. Мне так не повезло, у меня даже прикладники (программисты!) иногда не способны непротиворечиво объяснить, что им нужно.
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Re[19]: Языки общего назначения не имеют смысла!
От: koodeer  
Дата: 16.04.12 18:47
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>На шаблонах С++ эту задачу можно решить довольно просто.

WH>Показать, как или сам хочешь подумать?

Я представляю в общих чертах, как это делается. Более того, есть готовые примеры:
http://www.rsdn.ru/forum/src/1824757.flat.aspx
Автор: CrystaX
Дата: 06.04.06
— C++.
http://www.rsdn.ru/forum/src/1823225.flat.aspx
Автор: Oyster
Дата: 05.04.06
— Nemerle.
В своё время я очень заинтересовался этими двумя примерами.

Кстати, хотелось бы, чтобы нечто подобное было включено в стандартную библиотеку Немерла.


WH>В случае с С++ это не проблема. Если в класс засунуть один double то там ничего кроме него не будет.


Ну, хотелось бы не просто одно значение в классе. Нужно чтобы, например, при делении напряжения на сопротивление получалась сила тока.
Re: Языки общего назначения не имеют смысла!
От: org_256  
Дата: 16.04.12 18:49
Оценка:
я тысячный :-P походу
Re[19]: Языки общего назначения не имеют смысла!
От: koodeer  
Дата: 16.04.12 18:53
Оценка:
Здравствуйте, netch80, Вы писали:

N>Видимо, ты давно последний раз видел C++.


Да, давно. Последние годы сижу на дотнете.


N>Если размерность значения определена в его типе, то достаточно легко получить и контроль во время компиляции (причём оно может, например, разрешить присвоить скорости произведение ускорения на время и в то же время запретить присвоение ей массы), и в то же время единственным данным внутри класса будет значение величины — например, типа double — и после оптимизации всё это выродится в простейшие операции со скаляром с плавающей точкой.


N>Попробуй сам (только на современных компиляторах, а не образца 95-го года) и удивись.


А это будет сильно проще этого примера: http://www.rsdn.ru/forum/src/1824757.flat.aspx
Автор: CrystaX
Дата: 06.04.06
? Или именно реализация на шаблонах имеется в виду?


N>Для статически типизированного — да. Для динамически — нет.

N>Зависит именно от типизации.

Не, не, — динамическая типизация идёт лесом. Только статика, только проверки в компайл-тайме по максимуму.
Re[24]: Языки общего назначения не имеют смысла!
От: vdimas Россия  
Дата: 16.04.12 19:02
Оценка: :)
Здравствуйте, Sinclair, Вы писали:


V>>Дальше лень расписывать, пока было расписано подвыражение:

V>>select ManagerID, sum(Orders.Amount) from Orders where Orders.OrderDate between '20100101' and '20101231' group by ManagerID;
S>Отлично. Пока что SQL рвёт библиотеку 1 к 3м по компактности и читаемости.

Это пока нам не надо повторно использовать код. А то в итоге может оказаться наоборот 30 к 1 в итоге.


S>И это у вас ещё нет никаких попыток разрешить переписывания и оптимизации запроса внутри библиотеки — ваши предикаты это всего лишь функторы, а не Expression Trees.


V>>Можно спросить, что ты хотел узнать?

S>Да я-то ничего нового не узнал. Я хотел вам показать разницу между DSL и библиотекой, нарисованной на GPPL. Надеюсь, показал.
V>>На Клиппере пожестче было в свое время — никто не жаловался. И рвали по быстродействию любые базы, бо скомпилированный код многократно быстрее интерпретируемого работает.
S>
S>Вообще-то на клиппере как раз было помягче, т.к. всё таки это DSL, специально заточенный на обработку данных — пусть и чрезмерно императивный.

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


V>>>>Если же ты о перезаписи операций и прочей оптимизации — то это совсем отдельные операции, которые тоже, впрочем, достаточно формализованы.

S>>>Хотелось бы, чтобы перезапись операций и прочая оптимизация были не хуже, чем в SQL.

V>>Это нужен подход №2, когда выражение дается в виде декларации и доступно затем для аналитических вычислений. Тогда точно так же как показано выше в синтаксисе, но пусть select, from, transform и т.д. являюся не вызовами на обработку коллекций, а конструкторами узлов графа операций (аналог AST). Добавится лишь еще одна команда, нечто типа:

V>>
V>>auto resultingCollection = execute(result);
V>>

S>Что-то меня гложут тяжкие сомнения про то, что это так легко сделать, как вы пишете.

Почему? Смотрел на boost::lambda? Они почти весь синтаксис С++ умудрились сделать как генератор работающего AST. Отличный пример того, как это надо делать и стартовая точка для своих наработок.

Ес-но, для каждого выражения — свой узел. Вот здесь в двойных скобках приводил в примере именно генерацию AST, которое исполняется "потом":
( (_1.managerId=_2.first, _1.amount=sum(_2.second, &Order::amount)) )


_1, _2 — это глобальные placeholders из boost::lambda. В двойный скобках потому, что используется operator,() (оператор "запятая"), для перечисления последовательности действий в лямбде. Но синтаксис вызова ф-ии "проглотит" эти запятые в качестве разделителей нескольких аргументов, в то время как аргумент только у нас только один — это лямбда, вызываемая для построчных трансформаций.


S>Скажем, Версанту потребовалось всё-таки приделать свой парсер C++, чтобы обойти ограничения языка. Для AST недостаточно скормить в between указатель на член класса — надо каким-то образом дать возможность среде определить, что это за член класса такой, и поднять всю нужную метадату.


Как раз для приведенной мною ф-ии between ничего не нужно в отличие от генерации трансформаторов для проекций, продукций и пересечений, т.к. это просто перегрузка ее сигнатуры для случая на указателя на мембер, которая должна конструировать MemberBetweenPredicate (кстате, приведенный исключительно с целью показать, во что превратится вызов between).

Если бы я писал не торопясь, то увидел бы, что некая ф-ия приведения 'cdate' не нужна, достаточно, чтобы тип переменной-мембера имел нужный конструктор от одного аргумента, который можно вызвать как explicit.

Вот полный код для перегрузки сигнатуры between для указателя на мембер:
template<typename Entity, typename Value, typename Arg1, typename Agr2>
struct MemberBetweenPredicate<Entity, Value> between(Arg1 agr1, Value Entity::*member, Arg2 arg2) {
  MemberBetweenPredicate<Entity, Value> tmp = { member, { Value(arg1), Value(arg2) } };
  return tmp;
}


Теперь, при наличии у некоего типа, используемого для представления даты, конструктора от С-строки, можно писать еще короче:
between("20100101", &Order::orderDate, "20101231")
Re[26]: Языки общего назначения не имеют смысла!
От: koodeer  
Дата: 16.04.12 19:09
Оценка:
Здравствуйте, AndrewVK

Я сейчас почитал в соседней теме "DSL — мысли", что пишет Влад:

3. DSL есть всегда, так как любая модель предметной области в программе — это DSL. DSL, уважаемые, это в первую очередь ЯЗЫК. Модель ни разу не язык. С моделью можно работать через API. А DSL как раз и предназначен для того, чтобы корявое и не имеющее четких границ API заменить на четкий язык позволяющий заполнить эту модель конкретными данными. Простой пример — реализация КА (конечного автомата) — это модель. А язык позволяющий описывать состояния и переходы КА — это DSL.


Я понял часть своих заблуждений. Я действительно путаю модель и язык.
Собственно, для того я и вступил в обсуждение, чтобы разъяснить для себя самого неясные вопросы. Постепенно туман рассеивается.
Благодарю за потраченное время.
Re[20]: Языки общего назначения не имеют смысла!
От: WolfHound  
Дата: 16.04.12 19:13
Оценка:
Здравствуйте, koodeer, Вы писали:

K>Ну, хотелось бы не просто одно значение в классе. Нужно чтобы, например, при делении напряжения на сопротивление получалась сила тока.

Так по твоей ссылке код на С++ это и делает.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[26]: Языки общего назначения не имеют смысла!
От: vdimas Россия  
Дата: 16.04.12 19:54
Оценка:
Здравствуйте, AndrewVK, Вы писали:

V>>Зато прекрасно справляется параллельный LR(1)


AVK>Не справляется. Там есть места, парсить которые можно только с откатами, за фиксированное число лексем определить нужное правило нельзя. К примеру, IN предикат бывает двух типов — когда в скобках список выражений и когда подзапрос. Т.е. может быть такое:

AVK>
AVK>WHERE x IN (SELECT * FROM ys)
AVK>...
AVK>WHERE x IN (SELECT COUNT(*) FROM ys, SELECT COUNT(*) FROM zs)
AVK>

AVK>Это две разных синтаксических конструкции, одна "IN" "(" <value_list> ")", другая "IN" <subquery>, но отличить их парсер, могущий заглядывать на фиксированное количество лексем, в точке перед скобкой не может в принципе. Нужно заглядывать вперед по правилу с subquery, и только если не получилось его отматчить, идти по ветке value_list. Т.е. нужны откаты.
AVK>И таких вещей несколько штук даже в sql'92 есть.

Я знаю, но дело в том, что к концу выражения "останется" только один вариант, т.к. грамматика SQL однозначна. Поэтому я упомянул параллельный LR(1). В нем в месте конфликта происходит размножение текущего состояния вычислителя (полученные копии, кстати, эффективно делят стек предыдущих вычислений), затем "ошибочные ветки" умрут сами собой к концу выражения или еще раньше.

Я все время забываю, что у этой разновидности LR(k) есть собственное название GLR, т.к. сам переизобрел такой способ парсинга "неоднозначных где-то в середине выражений" на основе LR(1) в последней трети 90-х, когда еще не было у нас нормального интернета. Кстате, тогда же и убедился, что для техники параллельного разбора достаточно k=1 для любой однозначной грамматики, т.е. реализация GLR-алгоритма на основе LR(k) автомата даже в наколенном варианте выходит весьма примитивна из-за k=1 и располагает к экспериментам. К тому же работает шустро на однозначных участках входных цепочек, где разбор не уступает скорости работы какому-нить лексическому анализатору по регулярной грамматике.



V>>И вообще, любые параллельные парсеры для этого дела подойдут, например Эрли.

AVK>Ты под параллельными понимаешь парсеры с откатами (параллельным разбором правил) что ли? Тогда LL(k) или LR(k) такие парсеры называть некорректно.

Таки LR(k) — это разбор вширь, а не вглубь, как LL(k). Поэтому LR-парсеры и просятся на параллельность.
Эрли я упомянул как известный параллельный парсер, который 100% справится с задачей, хоть он и нисходящий. Конечно, он не LL(k). Просто есть несколько его готовых реализаций, включая на этом сайте (и мой чуть допиленный вариант, форкнутый с этого сайта ), и был подробный разбор принципов его работы. Т.е. это лишь пример того, что ничего страшного в плане парсинга не ожидает.


V>>Под простотой грамматики я имел ввиду малое кол-во правил для описания обсуждаемого оператора SELECT


AVK>В SQL'92, емнип, больше 6 сотен только для селекта. У меня, когда я выкинул все гавно типа указания кодировок и устаревших форм различных операторов, все равно больше сотни получилось.


Понятно... я навскидку больше пары десятков не вспомню...

Опять же, мы же обсуждали свой собственный DSL, лишь похожий на SQL, а разработка поддерживаемого этим DSL синтаксиса могла бы быть, скажем так, очень пошаговой. Ведь на каждую синтаксическую конструкцию необходимо иметь работающую трансформацию.


AVK>Но, на самом деле, парсер это фигня, мизерная часть от общего объема транслятора. Один ресолвер типов по трудоемкости в разы больше.


У меня однажды с полпинка заработала аналогичная задача, после перекидывания ее на Пролог. Т.е. захостил движок пролога в программе, скормил ему правила вывода + структуру фактических выражениq с неизвестными и он разресолвил мне все неизвестные. Причем, очень удобно, если больше одного решения по каждому неизвестному — то неоднозначность. Если нет решений — то нет. Круто. С тех пор я настойчиво рекомендую во всех этих обсуждениях использовать для вывода типов любой движок для программирования в ограничениях, т.е. взять готовую часть логического вывода, чтобы не писать ее самому. Ты ведь всё-равно ручками писал точно такой же перебор, только захардкоженный, т.е. даже не столь гибкий и легкий в экспериментах. Ну... если только не догадался декларативно выделить правила и заставить работать "решатель" поверх них, тогда беру свои слова назад насчет "захардкоженный", но не беру насчет "ручками".

Когда копнул эту тему чуть позже — увидел довольно много готовых движков и даже новых языков на эту тему.


V>>, т.е. можно закодить LR(1) врукопашную по системе правил — это будет вполне обозримый объем работ на несколько вечеров.


AVK>С учетом построения нормального AST и промышленного качества кода, я бы сказал пару недель. У опытного человека. Ну и LR в такой ситуации не лучший выбор — диагностика ошибок, понимаешь ли.


Я уже многократно видел мнение, что диагностика ошибок у LR слабовата... Не всегда это так. Это так у "глубоких" выражений, где парсер дает ошибку не в том месте, где человек допустил ошибку. Но каждый оператор SQL — максимум двухуровневый (операторы существования), и сами выражения редко более чем в 2-3 уровня склыдваются, если только не в join, что не есть в глубину. ИМХО вполне пойдет. У LR(k) будет точно такая же диагностика как у табличного LL(k), т.к. в точке возникновения ошибки будут доступны возможные успешные терминалы + ветки продолжения удачного разбора, точно так же, как доступен список успешных направляющих терминалов + соотв. веток разбора для LL(k).


V>>Именно что. Но ведь самый популярный контраргумент против разработки самописных DSL — якобы сложность разработки парсера.


AVK>Не знаю у кого он популярный. Наверное у тех, кто периодически озвучивает тут очередную гениальную идею по хранению исходников в виде отпарcенного AST.


V>>На самом деле, остальные 95% — они тоже не с 0-ля будут писаны в реальной разработке. К тому моменту, когда созрели до DSL, обычно уже есть много из готовой инфраструктуры и понимания происходящего, которое теперь надо "просто чуть по-другому оформить".


AVK>Ну, у меня такой проект до первого рабочего прототипа занял примерно 6 человекомесяцев. Потом еще пару пришлось потратить на переделку мест, где я сам же и схалтурил. Ну и еще месяца 4 в сумме ушло на докручивание нового функционала, в основном не мной.


Надеюсь, повторное использование разработанной технологии в разных проектах были? Ну или сам проект кастомизируемый под разных заказчиков (что фактически одно и то же)?
Понятно, что вложения должны давать отдачу. Например, от объема целевой задачи могла зависеть полнота поддержки исходного SQL. Мы в до-LINQ времена на перегрузках операторов C# делали генератор SQL для своей ORM на основе тогда еще RFD под 3 SQL-диалекта и развивали этот движок весьма пошагово, по мере поступления новых требований от всё новых и новых проектов, где он многократно использовался.
Re[24]: Языки общего назначения не имеют смысла!
От: mrTwister Россия  
Дата: 16.04.12 21:10
Оценка: 58 (1)
Здравствуйте, AndrewVK, Вы писали:

AVK>Здравствуйте, mrTwister, Вы писали:


T>>*]код очень трудно читаем. что он делает и зачем он нужен понять трудно.


AVK>Я легко прочел? И не очень понятно, что там так трудно читаемо.


Я совершенно не могу понять, что делает этот кусок кода:

IInventoryCardObject invCardObj = invAfter.GetInventoryCardObject();
if (invCardObj != null)
{
    var card = ((IPersistedObject)invCardObj).Master as IInventoryCardBase;
    if (card is IAccrualAccountingInventoryCard)
        Manager.DeleteObject((IPersistedObject)invCardObj);
    else if (!cardsDeleteSet.Contains(card))
        invCardObj.Inventory = inv;
}
inv.ChangesHistory = null;
ChangeInventoryActualStateInDocuments(invAfter, inv);
Manager.DeleteObject((IPersistedObject)invAfter);


Это просто взрыв мозга

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

T>>*]кучи даункастов


AVK>Не куча, а несколько. И это особенность платформы. Можешь просто проигнорировать.


Я насчитал 11 явных и неявных даункастов. Это очень много, код считай нетипизирован. Про особенность платформы — все мы знаем, что любую проблему в CS можно решить введением еще одного уровня абстракции. Причем совсем не обязательно этому уровню абстрацкии быть DSLем.

T>>*]кучи null'ей, которые в разных случаях имеют неявный смысл


AVK>Непонятно. Современные БД в принципе увязаны с null.


Совсем не обязательно тащить в прикладной код бизнес-логики потроха и особенности работы с БД.

T>>а во второй оставили низкоуровневый лапшу-код


AVK>Почему низкоуровневый?


Потому что API вашей платформы выглядит весьма гибким и низкоуровневым, о чем свидетельствует, например, обилие даункастов.

T>>*]напрашивается вынос из метода 3-х 4-х подпрограмм


AVK>Зачем выносить то, что встречается ровно один раз из метода меньше экрана размером?


Затем, чтобы читатель мог бы быстро понять в общем, что делает код и опускаться до деталей только тогда, когда они его действительно интересуют.

T>>*]Использование бессмысленных идентификаторов


AVK>Каких именно?


obj

T>>*]Можно было бы обойтись без модификаций локальной переменной (cardsDeleteSet)


AVK>Зачем?


Чтобы код было легче читать. Сейчас чтобы понять, что происходит приходится искать все места использования переменной в весьма "жирном" коде, искать, где переменная модифицируется, а где затем читается.


Вообще, я бы отрефакторил код, чтобы он в конце-концов выглядел как-то так:

var documentsAndInventories = (
    from document in Manager.Get(objectsIds)
    from inventory in document.GetObjects().Cast<IInventory>
    select new {document, inventory} ).ToArray();
    
var inventories = (from item in documentsAndInventories select new {item.inventory}).ToArray();
var inventoriesAndTheirOperations = (from inventory in inventories select new {inventory, GetInventiryOperations(inventory)}).ToArray();

ValidateForLateOperations(inventoriesAndTheirOperations);
ValidateForInvalidLinks(inventories);

var cardsThatWillBeDeleted = DeleteInventoryOperations(inventoriesAndTheirOperations);
ClearInventoryHistory(inventories, cardsThatWillBeDeleted);
ModifyInventoryResponsiblePersonAndStructuralSubdivision(documentsAndInventories);
DeleteCards(cardsThatWillBeDeleted);
лэт ми спик фром май харт
Re[25]: Языки общего назначения не имеют смысла!
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 16.04.12 21:54
Оценка:
Здравствуйте, mrTwister, Вы писали:

T>Я совершенно не могу понять, что делает этот кусок кода:


T>
T>IInventoryCardObject invCardObj = invAfter.GetInventoryCardObject();
T>if (invCardObj != null)
T>{
T>    var card = ((IPersistedObject)invCardObj).Master as IInventoryCardBase;
T>    if (card is IAccrualAccountingInventoryCard)
T>        Manager.DeleteObject((IPersistedObject)invCardObj);
T>    else if (!cardsDeleteSet.Contains(card))
T>        invCardObj.Inventory = inv;
T>}
T>inv.ChangesHistory = null;
T>ChangeInventoryActualStateInDocuments(invAfter, inv);
T>Manager.DeleteObject((IPersistedObject)invAfter);
T>


T>Это просто взрыв мозга


Не вижу никакого взрыва. Этот код просто лапочка по сравнению с тем, что местами попадается, скажем, в решарпере Типа нескольких вложенных циклов по графу, на который наложены и неявно учитываются контролируемые только в рантайме ограничения, внутри которых несколько goto, причем в разные точки. Вот это да, взрыв моска. А тут линейная логика.
Ну давай посмотрим:
IInventoryCardObject invCardObj = invAfter.GetInventoryCardObject();

Получаем объект инвентаризации из истории операции инвентаризации
if (invCardObj != null)

Если объект есть
var card = ((IPersistedObject)invCardObj).Master as IInventoryCardBase;

Берем карточку, по которой он инвентаризован
if (card is IAccrualAccountingInventoryCard)
    Manager.DeleteObject((IPersistedObject)invCardObj);

Здесь мои скудные знания бухгалтерии меня подводят, но суть понятна — удаляем объект инвентаризации, если он к определенному виду принадлежит. Прикладники тут, кстати, накосячили — приведение лишнее.
else if (!cardsDeleteSet.Contains(card))
        invCardObj.Inventory = inv;

Иначе проверяем наличие в хешике, который мы чуть раньше заполняли, и если совпало, то в детейле инвентарной карточки заменяем ссылку на справочник инвентаризуемых объектов.
inv.ChangesHistory = null;

Обнуляем историю инвентаризации
ChangeInventoryActualStateInDocuments(invAfter, inv);

Название метода вполне говорящее.
Manager.DeleteObject((IPersistedObject)invAfter);

Удаляем инвентаризационную операцию
Это, собственно, типичная бизнес-логика. Далеко не самая запутанная, уж поверь. И ее то как раз нужно сохранить, это входящее требование. А вот как ее более красиво записать — вопрос.

AVK>>Не куча, а несколько. И это особенность платформы. Можешь просто проигнорировать.


T>Я насчитал 11 явных и неявных даункастов.


Где? В DeleteObject даункаст лишний. Даункаст при обращении к Master — технологическая особенность, связанная с распределенностью системы и едиными интерфесами и в клиентском и в серверном коде. Согласен, проблема, но ее не так то легко вылечить. А as/is — это просто проверка дискриминанта, который выражен в виде реализации тех или иных интерфейсов.

AVK>>Непонятно. Современные БД в принципе увязаны с null.

T>Совсем не обязательно тащить в прикладной код бизнес-логики потроха и особенности работы с БД.

Согласен. Но альтернатив как то недофига. Можно, наверное, maybe monad использовать, да. Но тут скорее не dsl нужен, а нормальный допил C#. Штука то предельно универсальная.

T>>>а во второй оставили низкоуровневый лапшу-код

AVK>>Почему низкоуровневый?

T>Потому что API вашей платформы выглядит весьма гибким и низкоуровневым, о чем свидетельствует, например, обилие даункастов.


Это не API платформы, это сознательно сделанные на прикладном уровне решения. API платформы это Get и DeleteObjects.

T>>>*]Использование бессмысленных идентификаторов


AVK>>Каких именно?


T>obj


InventaryObject это потому что оно так и называется — объект инвентаризации, а не потому что это какая то неведомая фигня типа System.Object. Так что вполне осмысленный.


T>>>*]Можно было бы обойтись без модификаций локальной переменной (cardsDeleteSet)


AVK>>Зачем?


T>Чтобы код было легче читать. Сейчас чтобы понять, что происходит приходится искать все места использования переменной в весьма "жирном" коде, искать, где переменная модифицируется, а где затем читается.


Переменная модифицируется ровно один раз, при объявлении. Потом меняется содержимое самого хеша, а не переменной. И использование вполне стандартное — запоминаем в цикле обхода, потом запомненное используем для проверки. Такого кода, скажем, внутри System.Enumerable до попы, хотя, вроде как, весьма приличные спецы писали.

T>Вообще, я бы отрефакторил код, чтобы он в конце-концов выглядел как-то так:


T>[c#]

T>var documentsAndInventories = (
T> from document in Manager.Get(objectsIds)
T> from inventory in document.GetObjects().Cast<IInventory>
T> select new {document, inventory} ).ToArray();

Можно. Но линк для прикладников, все же, тяжеловат. Со временем, впрочем, должны научится, сейчас довольно вменяемых товарищей набрали. Было намного хуже, уж поверь.

T>var inventories = (from item in documentsAndInventories select new {item.inventory}).ToArray();

...

Спасибо за потраченное время.
... << RSDN@Home 1.2.0 alpha 5 rev. 31 on Windows 7 6.1.7601.65536>>
AVK Blog
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.