[HN Gopher] BrainFlood: Runtime code generation via reflection i...
       ___________________________________________________________________
        
       BrainFlood: Runtime code generation via reflection in .NET
        
       Author : thunderbong
       Score  : 69 points
       Date   : 2025-01-26 08:05 UTC (2 days ago)
        
 (HTM) web link (sbox.game)
 (TXT) w3m dump (sbox.game)
        
       | antithesis-nl wrote:
       | Ah, yes, this is delightfully useless! Well, maybe good for
       | stress-testing language tooling (that single huge type expressing
       | the Mandelbrot generator is... something to behold), but mostly
       | just cool-that-this-can-be-done.
       | 
       | Another cool thing that I learned about via this post (as I was
       | wondering about the .scene files in the GitHub repo) is this
       | whole ecosystem:
       | 
       | > S&box is coded in C#. Under the hood, it uses the Source 2
       | engine (CS2, HL:Alyx, DOTA2) and some of its systems: rendering,
       | resources, physics, and audio
       | 
       | And people say there is no more Good Stuff on the Internet...
        
       | pjc50 wrote:
       | This is quite something. I suspect this person has a C++
       | background, because the thing where they're abusing the generic
       | type system to do arithmetic is very much more like C++ template
       | libraries than something you normally see in C#. The advantage
       | seems to be that you can use MakeGenericType() in situations
       | where the normal bytecode Emit() isn't available?
        
         | kittoes wrote:
         | I wouldn't exactly call it "normal", but that's partially
         | because a lot of C# developers still don't know about the
         | relatively new generic maths feature. Those who are familiar
         | regularly "abuse" the system in a similar way because that's
         | one of the major benefits of it. We don't necessarily
         | reimplement basic arithmetic using the type system, but we
         | regularly hoist generic constants into static properties in
         | order to convince the compiler to behave the way we expect. For
         | example: _T.PopCount(value: T.AllBitsSet)_ is a safe and
         | generic way to express the size of a binary integer as a
         | constant.
        
           | neonsunset wrote:
           | > For example: T.PopCount(value: T.AllBitsSet) is a safe and
           | generic way to express the size of a binary integer as a
           | constant.
           | 
           | Despite the name, 'Unsafe.SizeOf<T>()` is the safe and
           | preferred way to do this - it is guaranteed to be a compiler
           | constant (in the past you'd say "JIT constant" but you can no
           | longer assume that with the advent of NativeAOT).
           | 
           | It's a bit unfortunate because much like with MemoryMarshal,
           | not all methods are equally unsafe. Some are benign or safe
           | like this one, same are Unsafe.As or, worse,
           | Unsafe.AsPointer.
        
             | tialaramex wrote:
             | > Despite the name
             | 
             | Why even _have_ something labelled  "Unsafe" which is in
             | fact safe ? Genuine question. What lead to this choice?
        
               | kittoes wrote:
               | The reasoning is generally that using SizeOf implies one
               | is doing unsafe things. Why do you need the size of
               | something in managed code? What would you do with that
               | information?
               | 
               | Not that I necessarily agree with the decision myself,
               | but that's the argument made by others.
        
       | Timwi wrote:
       | Sounds like an awesome article, but it's unreadable on mobile
       | (cut off on both sides) so I'll have to wait to read it until I
       | get to a PC. Might be worth fixing
        
         | nguyenkien wrote:
         | Your mobile browser doesn't have reader view?
        
           | gwbas1c wrote:
           | You shouldn't have to jump through hoops to read an article
           | on a phone. It's 2025; mobile browsers have been mainstream
           | since 2007.
        
         | maushu wrote:
         | Desktop mode in mobile seems to work fine.
        
           | recursive wrote:
           | The point is that normal mode doesn't.
        
             | gpvos wrote:
             | Looks fine to me (Fennec 134 on Android).
        
         | saurik wrote:
         | Maybe it has been fixed, but the article currently looks fine
         | for me on an iPhone.
        
       | souenzzo wrote:
       | Feels like a brainfuck interpreter version of magic(1), a
       | clojureCLR JIT compiler implemented via macro.
       | 
       | 1 https://github.com/nasser/magic
        
       | neonsunset wrote:
       | > Practical .NET Optimization Abuse
       | 
       | This is not abuse, it's intended behavior, standard library
       | itself likes to use it a lot internally. That's also how generics
       | work in Rust!
       | 
       | This can be pushed further by passing data by ref's. You can also
       | easily allocate structs in unmanaged heap (aka malloc and free)
       | and then pass them by `ref` without using unsafe (save for
       | construction and alloc/free). Just don't do it for structs which
       | contain gcrefs. C# can lean very heavily into systems programming
       | :)
       | 
       | There have also been a large amount of struct optimizations
       | across the last few versions. So it is not a coincidence that
       | RyuJIT/ILC can trade blows with LLVM (not always but still!).
       | 
       | Edit: Oh god, I saw what this refers to. I take it back. There is
       | likely a better, idiomatic and compiler-friendly way haha.
        
       | MrLeap wrote:
       | This is fascinating! Code generation is a thing that's solved a
       | couple problems for me recently. The way I do it never feels
       | great. Whenever I want to cache a big dictionary literal, I tend
       | to generate the code as a string and write it to a file. I've yet
       | to find a compelling upgrade that checks all the boxes. (The
       | generated side has run in the kneecapped .net for unity, although
       | the generator doesn't necessarily.)
       | 
       | I'm going to dig into your implementation.
        
         | kkukshtel wrote:
         | You could source generate this directly into your code instead
         | of dealing with file IO. Newer versions of Unity support source
         | generators:
         | 
         | https://docs.unity3d.com/6000.0/Documentation/Manual/create-...
        
       | whizzter wrote:
       | This is quite cursed, but does show that the .NET runtime system
       | and JIT seems fairly robust even in the presence of this
       | stupidity.
        
       | MarkSweep wrote:
       | This is great and despite what the article says, an actually
       | useful technique. The reason this performs well is the .NET
       | runtime does monomorphization when the generic type parameters
       | are value types (primitive types like int or user-defined
       | structs). In modern .NET you would use static abstract methods
       | interface methods to implement this feature. But if you have to
       | run on the old Windows-only .NET Framework, you need to use the
       | approach used in BrainFlood. See this article [1] for more
       | details. An example of an official .NET library that uses this
       | technique on .NET Framework is TensorPrimitives. See this file
       | [2], the structs are defined at the bottom.
       | 
       | [1]: https://blog.stephencleary.com/2022/10/modern-csharp-
       | techniq...
       | 
       | [2]:
       | https://github.com/dotnet/runtime/blob/main/src/libraries/Sy...
        
       ___________________________________________________________________
       (page generated 2025-01-28 23:01 UTC)