Сообщение Re[74]: MS забило на дотнет. Питону - да, сишарпу - нет? от 14.09.2021 17:13
Изменено 14.09.2021 17:16 vdimas
Re[74]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>А как вообще сюда напишешь расширение, если Expression порождает сам компилятор?
S>Вот так: https://github.com/bartdesmet/ExpressionFutures/tree/master/CSharpExpressions
Как я и сказал — переделывать сам компилятор:
S>То есть сами Expression есть, а вот компилятор их порождать не умеет.
О чём и речь.
Потому что у меня изначально, еще с выходом Linq, появилась идея попробовать подставить свои Expression, типа как можно делать свой AsyncMethodBuilder, но я не нашёл как.
У меня были свои наработки по "работающему" AST, свои Add/Mul/Const и т.д.
Что-то вроде:
Выражение с параметром
x + 42
порождает тип:
AddInt<Variable<int>, Const<int>>
Т.е. тоже пользовал тот факт, что джит для value-типов генерит уникальный код без боксинга.
Довольно шустро считало, кстате.
V>>Т.е. блоки для Expression нельзя.
S>Да, это хорошо известный факт. Мы это обсуждали в прошлый раз в ветке про linq2d.
Блоки содержатся в объектной иерархии Expression, просто не покрыты компилятором.
И еще много чего содержится, что не покрыто.
S>С точки зрения применения Expression Trees для разнообразной работы вроде "Давайте пользователь соберёт абстрактный pipeline обработки каких-то данных, а я из него сделаю монолитный эффективный метод без лишних аллокаций" это плохо.
Именно.
S>С точки зрения "я хочу писать Queryable Provider" это хорошо. Потому, что мне не нужно писать код для обработки случаев вроде
S>
Но можно сделать так:
Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии.
S>Коротко, там есть два основных класса проблем:
S>1. Не все языковые конструкции имеют аналог в виде Expression.
Ну, это понятно, особенно в деле unsafe.
Непонятно, почему поддержаны не все уже имеющиеся виды Expression.
S>2. Не все типы Expression (даже из стандартной библиотеки) можно породить компилятором из лямбда-синтаксиса.
Ага, в моём примере MyPredicate нельзя было объявить локальной статической ф-ией.
S>Вот это решается только коммитом в компилятор шарпа.
О чём и речь — еще пилить и пилить.
S>Актуальность каждой из проблем зависит от решаемой задачи.
А какая вообще у багов "актуальность"? ))
То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность.
V>>А как вообще сюда напишешь расширение, если Expression порождает сам компилятор?
S>Вот так: https://github.com/bartdesmet/ExpressionFutures/tree/master/CSharpExpressions
Как я и сказал — переделывать сам компилятор:
the C# compiler changes required to support assignment of lambda expressions containing those language constructs to an Expression<TDelegate> is maintained separately in the ExpressionTrees branch of my Roslyn fork.
S>То есть сами Expression есть, а вот компилятор их порождать не умеет.
О чём и речь.
Потому что у меня изначально, еще с выходом Linq, появилась идея попробовать подставить свои Expression, типа как можно делать свой AsyncMethodBuilder, но я не нашёл как.
У меня были свои наработки по "работающему" AST, свои Add/Mul/Const и т.д.
Что-то вроде:
interface IOperation<TResult>
{
TResult Execute();
}
IBinaryOp<TLeft, TRight, TResult> : IOperation<TResult>
where TLeft : IOperation<TLeft>
where TRight: IOperation<TRight>
{
public TLeft Left {get;}
public TRight Right {get;}
}
struct Const<T> : IOperation<T>
{
public readonly T Value;
public T Execute() => Value;
}
class Variable<T> : IOperation<T>
{
public T Value;
public readonly string Name;
public T Execute() => Value;
}
struct AddIntOp<TLeft, TRight> : IBinaryOp<TLeft, TRight, int>
where TLeft : IOperation<int>
where TRight: IOperation<int>
{
public TLeft Left {get;}
public TRight Right {get;}
public int Execute() => Left.Execute() + Right.Execute();
}Выражение с параметром
x + 42
порождает тип:
AddInt<Variable<int>, Const<int>>
Т.е. тоже пользовал тот факт, что джит для value-типов генерит уникальный код без боксинга.
Довольно шустро считало, кстате.
V>>Т.е. блоки для Expression нельзя.
S>Да, это хорошо известный факт. Мы это обсуждали в прошлый раз в ветке про linq2d.
Блоки содержатся в объектной иерархии Expression, просто не покрыты компилятором.
И еще много чего содержится, что не покрыто.
S>С точки зрения применения Expression Trees для разнообразной работы вроде "Давайте пользователь соберёт абстрактный pipeline обработки каких-то данных, а я из него сделаю монолитный эффективный метод без лишних аллокаций" это плохо.
Именно.
S>С точки зрения "я хочу писать Queryable Provider" это хорошо. Потому, что мне не нужно писать код для обработки случаев вроде
S>
S>from p in Person where {var s = new StringBuilder(); foreach(var ch in p.Name} if (p.IsLetterOrDigit) s.Append(ch); return s.ToString()=="John";} select p
S>Но можно сделать так:
internal record Person(string Name);
private static bool MyPredicate(string name) {
var s = new StringBuilder();
foreach(var ch in name) {
if(char.IsLetterOrDigit(ch))
s.Append(ch);
}
return s.ToString() == "John";
}
private static void Main() {
Person[] persons = {
new("++John++"),
new("Jo--hn"),
new("Andry")
};
var collection = from p in persons.AsQueryable() where MyPredicate(p.Name) select p;
foreach(var p in collection)
Console.WriteLine(p);
}Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии.
S>Коротко, там есть два основных класса проблем:
S>1. Не все языковые конструкции имеют аналог в виде Expression.
Ну, это понятно, особенно в деле unsafe.
Непонятно, почему поддержаны не все уже имеющиеся виды Expression.
S>2. Не все типы Expression (даже из стандартной библиотеки) можно породить компилятором из лямбда-синтаксиса.
Ага, в моём примере MyPredicate нельзя было объявить локальной статической ф-ией.
S>Вот это решается только коммитом в компилятор шарпа.
О чём и речь — еще пилить и пилить.
S>Актуальность каждой из проблем зависит от решаемой задачи.
А какая вообще у багов "актуальность"? ))
То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность.
Re[74]: MS забило на дотнет. Питону - да, сишарпу - нет?
Здравствуйте, Sinclair, Вы писали:
V>>А как вообще сюда напишешь расширение, если Expression порождает сам компилятор?
S>Вот так: https://github.com/bartdesmet/ExpressionFutures/tree/master/CSharpExpressions
Как я и сказал — переделывать сам компилятор:
S>То есть сами Expression есть, а вот компилятор их порождать не умеет.
О чём и речь.
Потому что у меня изначально, еще с выходом Linq, появилась идея попробовать подставить свои Expression, типа как можно делать свой AsyncMethodBuilder, но я не нашёл как.
У меня были свои наработки по "работающему" AST, свои Add/Mul/Const и т.д.
Что-то вроде:
Выражение с параметром
x + 42
порождает тип:
AddInt<Variable<int>, Const<int>>
Т.е. тоже пользовал тот факт, что джит для value-типов генерит уникальный код без боксинга.
Довольно шустро считало, кстате.
V>>Т.е. блоки для Expression нельзя.
S>Да, это хорошо известный факт. Мы это обсуждали в прошлый раз в ветке про linq2d.
Блоки содержатся в объектной иерархии Expression, просто не покрыты компилятором.
И еще много чего содержится, что не покрыто.
S>С точки зрения применения Expression Trees для разнообразной работы вроде "Давайте пользователь соберёт абстрактный pipeline обработки каких-то данных, а я из него сделаю монолитный эффективный метод без лишних аллокаций" это плохо.
Именно.
S>С точки зрения "я хочу писать Queryable Provider" это хорошо. Потому, что мне не нужно писать код для обработки случаев вроде
S>
Но можно сделать так:
Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии.
S>Коротко, там есть два основных класса проблем:
S>1. Не все языковые конструкции имеют аналог в виде Expression.
Ну, это понятно, особенно в деле unsafe.
Непонятно, почему поддержаны не все уже имеющиеся виды Expression.
S>2. Не все типы Expression (даже из стандартной библиотеки) можно породить компилятором из лямбда-синтаксиса.
Ага, в моём примере MyPredicate нельзя было объявить локальной статической ф-ией.
S>Вот это решается только коммитом в компилятор шарпа.
О чём и речь — еще пилить и пилить.
S>Актуальность каждой из проблем зависит от решаемой задачи.
А какая вообще у багов "актуальность"? ))
То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность.
V>>А как вообще сюда напишешь расширение, если Expression порождает сам компилятор?
S>Вот так: https://github.com/bartdesmet/ExpressionFutures/tree/master/CSharpExpressions
Как я и сказал — переделывать сам компилятор:
the C# compiler changes required to support assignment of lambda expressions containing those language constructs to an Expression<TDelegate> is maintained separately in the ExpressionTrees branch of my Roslyn fork.
S>То есть сами Expression есть, а вот компилятор их порождать не умеет.
О чём и речь.
Потому что у меня изначально, еще с выходом Linq, появилась идея попробовать подставить свои Expression, типа как можно делать свой AsyncMethodBuilder, но я не нашёл как.
У меня были свои наработки по "работающему" AST, свои Add/Mul/Const и т.д.
Что-то вроде:
interface IOperation<TResult>
{
TResult Execute();
}
IBinaryOp<TLeft, TRight, TResult> : IOperation<TResult>
where TLeft : IOperation<TLeft>
where TRight: IOperation<TRight>
{
public TLeft Left {get;}
public TRight Right {get;}
}
struct Const<T> : IOperation<T>
{
public readonly T Value;
public T Execute() => Value;
}
class Variable<T> : IOperation<T>
{
public T Value;
public readonly string Name;
public T Execute() => Value;
}
struct AddIntOp<TLeft, TRight> : IBinaryOp<TLeft, TRight, int>
where TLeft : IOperation<int>
where TRight: IOperation<int>
{
public TLeft Left {get;}
public TRight Right {get;}
public int Execute() => Left.Execute() + Right.Execute();
}Выражение с параметром
x + 42
порождает тип:
AddInt<Variable<int>, Const<int>>
Т.е. тоже пользовал тот факт, что джит для value-типов генерит уникальный код без боксинга.
Довольно шустро считало, кстате.
V>>Т.е. блоки для Expression нельзя.
S>Да, это хорошо известный факт. Мы это обсуждали в прошлый раз в ветке про linq2d.
Блоки содержатся в объектной иерархии Expression, просто не покрыты компилятором.
И еще много чего содержится, что не покрыто.
S>С точки зрения применения Expression Trees для разнообразной работы вроде "Давайте пользователь соберёт абстрактный pipeline обработки каких-то данных, а я из него сделаю монолитный эффективный метод без лишних аллокаций" это плохо.
Именно.
S>С точки зрения "я хочу писать Queryable Provider" это хорошо. Потому, что мне не нужно писать код для обработки случаев вроде
S>
S>from p in Person where {var s = new StringBuilder(); foreach(var ch in p.Name} if (p.IsLetterOrDigit) s.Append(ch); return s.ToString()=="John";} select p
S>Но можно сделать так:
internal record Person(string Name);
private static bool MyPredicate(string name) {
var s = new StringBuilder();
foreach(var ch in name) {
if(char.IsLetterOrDigit(ch))
s.Append(ch);
}
return s.ToString() == "John";
}
private static void Main() {
Person[] persons = {
new("++John++"),
new("Jo--hn"),
new("Andy")
};
var collection = from p in persons.AsQueryable() where MyPredicate(p.Name) select p;
foreach(var p in collection)
Console.WriteLine(p);
}Т.е., я не вижу смысла в таких ограничениях, которые обходится простым оформлением лямбды в виде внешней ф-ии.
S>Коротко, там есть два основных класса проблем:
S>1. Не все языковые конструкции имеют аналог в виде Expression.
Ну, это понятно, особенно в деле unsafe.
Непонятно, почему поддержаны не все уже имеющиеся виды Expression.
S>2. Не все типы Expression (даже из стандартной библиотеки) можно породить компилятором из лямбда-синтаксиса.
Ага, в моём примере MyPredicate нельзя было объявить локальной статической ф-ией.
S>Вот это решается только коммитом в компилятор шарпа.
О чём и речь — еще пилить и пилить.
S>Актуальность каждой из проблем зависит от решаемой задачи.
А какая вообще у багов "актуальность"? ))
То, что MyPredicate не может быть статической локальной ф-ией — это просто баг, неконсистентность.