Информация об изменениях

Сообщение 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

Как я и сказал — переделывать сам компилятор:

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

Как я и сказал — переделывать сам компилятор:

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 не может быть статической локальной ф-ией — это просто баг, неконсистентность.