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

Сообщение Re[2]: Source Generators C# от 04.10.2023 2:17

Изменено 04.10.2023 2:21 Разраб

Re[2]: Source Generators C#
Здравствуйте, Shmj, Вы писали:



S>Средний человек физически не способен на глубинном уровне понять код с множеством макросов.

Да что же тут сложного? Макросы это то что должно быть в каждом ЯП. Это самый крутой инструмент разработчика.

(defmacro writeln (&;rest args)
  `(progn
     (loop for e in '(,@args)
       do
          (format t "~A" e))
     (format t "~%")))

(defstruct person name)

(defgeneric hello (obj)
  (:documentation "Say hello to object."))

(defmethod hello ((obj person))
  (writeln "Hello, " (person-name obj) "!"))

(defvar p1 (make-person
        :name "Alice"))

(hello p1)
;;печатает символы вместо значений 
;;c:\tmp>sbcl --script mac.lisp
;;sbcl --script mac.lisp
;;Hello, (PERSON-NAME OBJ)

аналог writeln из паскаля на немерле на макросе:
#pragma indent 
// io.n
using System.Console;
macro writeln (params  a: array[expr])
    mutable exps = [];     
        foreach(e in a)
         exps = <[ Write($e); ]> :: exps;

    exps = <[ WriteLine();]> :: exps;
    exps = exps.Reverse();
    <[ { .. $exps } ]>
//main.n compile with reference to io.n (compiled to dll)   
writeln ("Name = ", "Alice", ", age = ", 23, ", student = ", true);

то же самое на F# на функциях и рефлексии:
open System
open Microsoft.FSharp.Reflection

let readln = Console.ReadLine
let writeln = fun a ->
    let args = if FSharpType.IsTuple(a.GetType()) then FSharpValue.GetTupleFields(a) else [|a|]
    let fmt = args |> Array.indexed |> Array.fold (fun s e -> s + (sprintf "{%d}" (fst e))) ""
    Console.WriteLine(fmt.Trim(), args)
let write = fun a ->
    let args = if FSharpType.IsTuple(a.GetType()) then FSharpValue.GetTupleFields(a) else [|a|]
    let fmt = args |> Array.indexed |> Array.fold (fun s e -> s + (sprintf "{%d}" (fst e))) ""
    Console.Write(fmt.Trim(), args)
    
[<EntryPoint>]
let main argv = 
    write ("Ваше имя:")
    let name = readln ()
    writeln ("Hello, ", name , "!")
    readln () |> ignore
    0 // return an integer exit code


и сравните с этим:
using Microsoft.CodeAnalysis;

namespace SourceGenerator
{
    [Generator]
    public class HelloSourceGenerator : ISourceGenerator
    {
        public void Execute(GeneratorExecutionContext context)
        {
            // Find the main method
            var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);

            // Build up the source code
            string source = $@"// <auto-generated/>
using System;

namespace {mainMethod.ContainingNamespace.ToDisplayString()}
{{
    public static partial class {mainMethod.ContainingType.Name}
    {{
        static partial void HelloFrom(string name) =>
            Console.WriteLine($""Generator says: Hi from '{{name}}'"");
    }}
}}
";
            var typeName = mainMethod.ContainingType.Name;

            // Add the source code to the compilation
            context.AddSource($"{typeName}.g.cs", source);
        }

        public void Initialize(GeneratorInitializationContext context)
        {
            // No initialization required for this one
        }
    }
}


сложнее в настройке в разы чем использование макросов в немерле. макрос как подпрограмма времени компиляция проходит такой же цикл как и обычная (отладка). кроме того всегда можно раскрыть макрос в исходники.
можно конечно страдать с функциями, но тут макры дают еще пару приемуществ — скорость работы, и простота технологии выраженная в отсутствии рефлексии в рантайме.
тут весь вопрос в том лететь или ползти. миллион мух выбрали второе. печалька ))
Re[2]: Source Generators C#
Здравствуйте, Shmj, Вы писали:



S>Средний человек физически не способен на глубинном уровне понять код с множеством макросов.

Да что же тут сложного? Макросы это то что должно быть в каждом ЯП. Это самый крутой инструмент разработчика.

(defmacro writeln (&;rest args)
  `(progn
     (loop for e in '(,@args)
       do
          (format t "~A" e))
     (format t "~%")))

(defstruct person name)

(defgeneric hello (obj)
  (:documentation "Say hello to object."))

(defmethod hello ((obj person))
  (writeln "Hello, " (person-name obj) "!"))

(defvar p1 (make-person
        :name "Alice"))

(hello p1)
;;печатает символы вместо значений 
;;c:\tmp>sbcl --script mac.lisp
;;sbcl --script mac.lisp
;;Hello, (PERSON-NAME OBJ)

аналог writeln из паскаля на немерле на макросе:
#pragma indent 
// io.n
using System.Console;
macro writeln (params  a: array[expr])
    mutable exps = [];     
        foreach(e in a)
         exps = <[ Write($e); ]> :: exps;

    exps = <[ WriteLine();]> :: exps;
    exps = exps.Reverse();
    <[ { .. $exps } ]>
//main.n compile with reference to io.n (compiled to dll)   
writeln ("Name = ", "Alice", ", age = ", 23, ", student = ", true);

то же самое на F# на функциях и рефлексии:
open System
open Microsoft.FSharp.Reflection

let readln = Console.ReadLine
let writeln = fun a ->
    let args = if FSharpType.IsTuple(a.GetType()) then FSharpValue.GetTupleFields(a) else [|a|]
    let fmt = args |> Array.indexed |> Array.fold (fun s e -> s + (sprintf "{%d}" (fst e))) ""
    Console.WriteLine(fmt.Trim(), args)
let write = fun a ->
    let args = if FSharpType.IsTuple(a.GetType()) then FSharpValue.GetTupleFields(a) else [|a|]
    let fmt = args |> Array.indexed |> Array.fold (fun s e -> s + (sprintf "{%d}" (fst e))) ""
    Console.Write(fmt.Trim(), args)
    
[<EntryPoint>]
let main argv = 
    write ("Ваше имя:")
    let name = readln ()
    writeln ("Hello, ", name , "!")
    readln () |> ignore
    0 // return an integer exit code


и сравните с этим:
using Microsoft.CodeAnalysis;

namespace SourceGenerator
{
    [Generator]
    public class HelloSourceGenerator : ISourceGenerator
    {
        public void Execute(GeneratorExecutionContext context)
        {
            // Find the main method
            var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);

            // Build up the source code
            string source = $@"// <auto-generated/>
using System;

namespace {mainMethod.ContainingNamespace.ToDisplayString()}
{{
    public static partial class {mainMethod.ContainingType.Name}
    {{
        static partial void HelloFrom(string name) =>
            Console.WriteLine($""Generator says: Hi from '{{name}}'"");
    }}
}}
";
            var typeName = mainMethod.ContainingType.Name;

            // Add the source code to the compilation
            context.AddSource($"{typeName}.g.cs", source);
        }

        public void Initialize(GeneratorInitializationContext context)
        {
            // No initialization required for this one
        }
    }
}


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