Сообщение Re[39]: EntityFramework - тормоз от 24.04.2015 15:27
Изменено 24.04.2015 15:35 Evgeny.Panasyuk
S>>>Ок, я понял. Обстоят чуть хуже, чем никак:
S>>>
S>>> auto x = select(apples.appleId, oranges.orangeId); // WTF is x???
S>>>
EP>>Это же простой пример не претендующий на полноту. При желании можно получить например такой синтаксис:
S>1. простой вопрос: так что же всё-таки есть в этом sqlpp, кроме добрых намерений? А то вот некоторые по соседству смело утверждают, что есть прямо таки всё и из коробки. А вы пишете про "при желании"...
Я показываю не sqlpp11, а технику которая может использоваться для создания структуры с необходимым набором полей (а не просто безликий котреж), причём наполняя её в зависимости от каких-либо compile-time условий.
S>Я, не имея С++ компилятора под рукой, склоняюсь к тому, что sqlpp11 умеет проверять только простейшие сценарии.
sqlpp11 я знаю только по нескольким примерам, умеет ли он или нет "сложные" сценарии — ручаться не могу. Тем не менее, если интересны какие-то конкретные моменты sqlpp11 — можем здесь разобрать.
S>2. более сложный вопрос: а за счёт чего и как мы планируем порождать типы и контролировать корректность статически?
За счёт того что у нас во время компиляции известны: структура таблиц, связи между ними, дерево выражения запроса — и для обработки этого есть язык времени компиляции полный по Тьюрингу.
S>Попробуйте написать простейший запрос типа "покажи мне всех менеджеров, которые продали больше среднего в своих отделах в прошлом году". На sql это пишется тривиально:
На чём? На sqlpp11 или показать абстрактный вариант compile-time EDSL?
S>Linq позволит мне разнести этапы определения CTE и сборки запроса, отчего код сильно выиграет в читаемости и редактируемости.
Разнести этапы составления дерева выражения времени компиляции по разным местам вообще не проблема.
Для этого даже не нужно ничего делать специально — достаточно только не мешать.
Пример:
// Terminal symbols:
struct Select {} select;
struct Where {} where;
// Nonterminal:
template<typename Left, typename Right> struct Pipeline {};
template<typename T, typename U>
auto operator|(T, U)
{
return Pipeline<T, U>{};
}
// Utility for print type at compile time:
template<typename T> void type_is(T);
int main()
{
// Create expression tree by parts, in different expressions:
// 1:
auto q1 = select | where;
// 2:
auto q2 = q1 | select;
// Print type of q2:
type_is(q2);
}
Результат:undefined reference to `void type_is<Pipeline<Pipeline<Select, Where>, Select> >(Pipeline<Pipeline<Select, Where>, Select>)'
Жирным выделен тип. Этот тип можно обрабатывать во время компиляции.
Например можем запретить построение выражения вида * | where | select | where | *:
// Process expression tree:
template<typename _>
struct CheckGrammar
{
using type = bool;
};
template<typename Left, typename Right>
struct CheckGrammar<Pipeline<Left, Right>>
{
using type = typename CheckGrammar<Left>::type; // Recurse to left sub-tree
};
template<typename _>
struct CheckGrammar
<
Pipeline<Pipeline<Pipeline<_, Where>, Select>, Where> // Pattern matching
>
{
using type = typename _::error_in_grammar_after;
};
template<typename T, typename U>
auto operator|(T, U)
{
auto result = Pipeline<T, U>{};
using run = typename CheckGrammar<decltype(result)>::type; // Run grammar check at compile-time
return result;
}
int main()
{
auto q1 = where | select | select; // OK
auto q2 = q1 | where; // OK
auto q3 = q2 | select | where; // ERROR
}
Вывод компилятора:Скрытый текст | |
| |
Подобное дерево можно обрабатывать как угодно. Результатом compile-time обработки, опять таки полной по Тьюрингу, может быть строка запроса.
Можно расширить пример полями из предыдущего примера, и наполнять ими struct в зависимости от структуры дерева выражения, отображать них результат запроса и т.д. и т.п.
S>При этом шаг вправо-влево будет отслеживаться компилятором, т.к. в процессе сборки дерева выводятся типы промежуточных результатов и всё проверяется.
Это тоже не проблема.
S>На первый взгляд, sqlpp не предлагает ничего интереснее констант для имён таблиц и полей.
В документации написано что есть под-запросы.
При этом повторюсь:
http://rsdn.ru/forum/flame.comp/6014725.1
Автор: Evgeny.Panasyuk
Дата: 14.04.15
EP>Изначально речь шла про принципиальную возможность. А возможно это не только в C++, но и например в D или Nemerle.
EP>Что же касается конкретного примера — я с СУБД вообще не работаю. Для создания полного примера мне придётся разбираться с одной из упомянутых выше библиотек — на первый взгляд то о чём я говорю там вполне реализуемо, но могут быть некоторые детали которые будут препятствовать реализации, что впрочем никак не будет означать принципиальную невозможность, и соответственно к изначальному тезису не имеет отношения.
EP>Если же есть сомнения в принципиальной реализуемости — то готов ответить на конкретные вопросы.
S>>>Ок, я понял. Обстоят чуть хуже, чем никак:
S>>>
S>>> auto x = select(apples.appleId, oranges.orangeId); // WTF is x???
S>>>
EP>>Это же простой пример не претендующий на полноту. При желании можно получить например такой синтаксис:
S>1. простой вопрос: так что же всё-таки есть в этом sqlpp, кроме добрых намерений? А то вот некоторые по соседству смело утверждают, что есть прямо таки всё и из коробки. А вы пишете про "при желании"...
Я показываю не sqlpp11, а технику которая может использоваться для создания структуры с необходимым набором полей (а не просто безликий котреж), причём наполняя её в зависимости от каких-либо compile-time условий.
S>Я, не имея С++ компилятора под рукой, склоняюсь к тому, что sqlpp11 умеет проверять только простейшие сценарии.
sqlpp11 я знаю только по нескольким примерам, умеет ли он или нет "сложные" сценарии — ручаться не могу. Тем не менее, если интересны какие-то конкретные моменты sqlpp11 — можем здесь разобрать.
S>2. более сложный вопрос: а за счёт чего и как мы планируем порождать типы и контролировать корректность статически?
За счёт того что у нас во время компиляции известны: структура таблиц, связи между ними, дерево выражения запроса — и для обработки этого есть язык времени компиляции полный по Тьюрингу.
S>Попробуйте написать простейший запрос типа "покажи мне всех менеджеров, которые продали больше среднего в своих отделах в прошлом году". На sql это пишется тривиально:
На чём? На sqlpp11 или показать абстрактный вариант compile-time EDSL?
S>Linq позволит мне разнести этапы определения CTE и сборки запроса, отчего код сильно выиграет в читаемости и редактируемости.
Разнести этапы составления дерева выражения времени компиляции по разным местам вообще не проблема.
Для этого даже не нужно ничего делать специально — достаточно только не мешать.
Пример:
// Terminal symbols:
struct Select {} select;
struct Where {} where;
// Nonterminal:
template<typename Left, typename Right> struct Pipeline {};
template<typename T, typename U>
auto operator|(T, U)
{
return Pipeline<T, U>{};
}
// Utility for print type at compile time:
template<typename T> void type_is(T);
int main()
{
// Create expression tree by parts, in different expressions:
// 1:
auto q1 = select | where;
// 2:
auto q2 = q1 | select;
// Print type of q2:
type_is(q2);
}
Результат:undefined reference to `void type_is<Pipeline<Pipeline<Select, Where>, Select> >(Pipeline<Pipeline<Select, Where>, Select>)'
Жирным выделен тип. Этот тип можно обрабатывать во время компиляции.
Например можем запретить построение выражения вида * | where | select | where | *:
// Process expression tree:
template<typename _>
struct CheckGrammar
{
using type = bool;
};
template<typename Left, typename Right>
struct CheckGrammar<Pipeline<Left, Right>>
{
using type = typename CheckGrammar<Left>::type; // Recurse to left sub-tree
};
template<typename _>
struct CheckGrammar
<
Pipeline<Pipeline<Pipeline<_, Where>, Select>, Where> // Pattern matching
>
{
using type = typename _::error_in_grammar_after;
};
template<typename T, typename U>
auto operator|(T, U)
{
auto result = Pipeline<T, U>{};
using run = typename CheckGrammar<decltype(result)>::type; // Run grammar check at compile-time
return result;
}
int main()
{
auto q1 = where | select | select; // OK
auto q2 = q1 | where; // OK
auto q3 = q2 | select | where; // ERROR
}
Вывод компилятора:Скрытый текст | |
| |
Подобное дерево можно обрабатывать как угодно. Результатом compile-time обработки, опять таки полной по Тьюрингу, может быть строка запроса.
Можно расширить пример полями из предыдущего примера, и наполнять ими struct в зависимости от структуры дерева выражения, отображать на них результат запроса и т.д. и т.п.
S>При этом шаг вправо-влево будет отслеживаться компилятором, т.к. в процессе сборки дерева выводятся типы промежуточных результатов и всё проверяется.
Это тоже не проблема.
S>На первый взгляд, sqlpp не предлагает ничего интереснее констант для имён таблиц и полей.
В документации написано что есть под-запросы.
При этом повторюсь:
http://rsdn.ru/forum/flame.comp/6014725.1
Автор: Evgeny.Panasyuk
Дата: 14.04.15
EP>Изначально речь шла про принципиальную возможность. А возможно это не только в C++, но и например в D или Nemerle.
EP>Что же касается конкретного примера — я с СУБД вообще не работаю. Для создания полного примера мне придётся разбираться с одной из упомянутых выше библиотек — на первый взгляд то о чём я говорю там вполне реализуемо, но могут быть некоторые детали которые будут препятствовать реализации, что впрочем никак не будет означать принципиальную невозможность, и соответственно к изначальному тезису не имеет отношения.
EP>Если же есть сомнения в принципиальной реализуемости — то готов ответить на конкретные вопросы.