[HN Gopher] Metaprogramming custom control structures in C (2012)
       ___________________________________________________________________
        
       Metaprogramming custom control structures in C (2012)
        
       Author : ingve
       Score  : 46 points
       Date   : 2021-07-09 09:08 UTC (1 days ago)
        
 (HTM) web link (www.chiark.greenend.org.uk)
 (TXT) w3m dump (www.chiark.greenend.org.uk)
        
       | adamnemecek wrote:
       | So much time has been spent on making C something that it's not.
       | Sure. It's interesting, but then some people start thinking that
       | this is the way you should be writing C.
        
         | MaxBarraclough wrote:
         | > So much time has been spent on making C something that it's
         | not.
         | 
         | GObject is a great example of this. It's a library for doing
         | OOP with C, rather than switching to C++. It's clunky enough
         | that they ended up making a whole new language which compiles
         | to C/GObject, called _Vala_.
         | 
         | Vala rarely gets attention these days, but it's worth reading
         | about.
         | https://en.wikipedia.org/wiki/Vala_(programming_language)
        
           | pjmlp wrote:
           | Here is another example, COM or as it originally started OLE.
           | 
           | Yes, basically it is C OO ABI, however only masochists would
           | use it as such.
           | 
           | Everyone else just reaches for VB 6, C++ (MFC, ATL, WRL, WIL,
           | C++/CX, C++/WinRT, yeah I know, so is WinDev....), .NET,
           | Delphi, C++ Builder, ...
        
             | MaxBarraclough wrote:
             | I have to admit ignorance on exactly what COM does. Doesn't
             | Direct3D (all versions including the latest) use COM
             | despite being essentially a C++-only API?
        
               | pjmlp wrote:
               | Yes, they are COM based APIs.
               | 
               | All modern Windows APIs use COM to great extent, anyone
               | that uses pure Win32 APIs is basically frozen in Windows
               | XP view of the world.
               | 
               | Mini-history lesson, initially there was DDE, which
               | allowed for basic IPC on Windows 3.x, then came OLE 1.0,
               | both required endless amount of C boiler plate.
               | 
               | Then someone realized that from all concepts, there was a
               | set of central ideas and Windows OO ABI was born, which
               | basically maps to structure with function pointers,
               | naturally with the same layout as Windows C++ compilers
               | organize their vtables when using single inheritance.
               | 
               | So then we had OLE 2.0, COM, OCX, ActiveX, mini-COM,
               | which are basically all the same, IUnknown interface with
               | three methods QueryInterface(), AddRef() and Release(),
               | everything else builds on top of that.
               | 
               | WinRT/UWP is COM updated with some of the ideas that were
               | actually behind .NET birth, so alongside IUnknown there
               | is IInspectable.
               | 
               | So on Windows any language that understands COM ABI (not
               | only C++) can make use of an OS wide OO ABI.
               | 
               | Then there are lots of things one can do with it,
               | regarding in which memory space those components run, how
               | many threads they use, security,...
               | 
               | Going back to the initial question, it is designed to be
               | called from C as well, but almost no one does it.
        
         | danlugo92 wrote:
         | 9 out of 10 times good old `doSomethingWith(foo: Foo)` style C
         | is better than c++/whatever `foo.doSomething()`.
        
           | BenFrantzDale wrote:
           | Contemporary C++ encourages this too. There's a place for
           | member functions--even convenience ones--but algorithms
           | operate on data structures; they needn't be part of the data
           | structures.
        
             | pjmlp wrote:
             | Since STL was introduced actually, even if functors were a
             | bit painful to write, however if you look at codebases like
             | Android, there is some catch up to do with modern times.
        
         | veltas wrote:
         | I played with this kind of C, and it seems to be attractive to
         | HN. Applying C's own (albeit limited) type-safety and
         | encapsulation features where I can, but not going too exotic or
         | trying too hard to be another language, seems to be the right
         | compromise for me.
        
       | atom3 wrote:
       | When I found out about this, I wrote some macros to replicate
       | some of the semantic of ISPC [1] in C++ as a fun experiment [2].
       | 
       | Of course it has no practical value but it was really cool to see
       | it was possible to do so.
       | 
       | [1] https://ispc.github.io/
       | 
       | [2] https://github.com/aTom3333/ispc-in-cpp-poc
        
       | glouwbug wrote:
       | I once back ported the core of the C++ STL to C to introduce
       | templated containers to C with some macro magic. I learned in the
       | end that I'm better off using C++
        
         | jstimpfle wrote:
         | Maybe you're just better off not porting the STL :P
        
           | glouwbug wrote:
           | It was a learning experience. And you're right, the real
           | learning experience was to not port the STL
        
         | kleton wrote:
         | klib? https://github.com/attractivechaos/klib
        
           | glouwbug wrote:
           | CTL. https://github.com/glouw/ctl
           | 
           | It's functionally blackbox compatible with the STL for the
           | major containers. Unless you're writing heap spaced firmware
           | where C++ with an STL isn't available I recommend you just
           | use modern day C++.
           | 
           | Unless, of course, you want blazing fast compile times!
        
             | ludamad wrote:
             | I'm curious about how much easier it is to optimize
             | compiler time for macros rather than templates here. In
             | theory they wouldn't be all that different, but in practice
             | it doesn't seem so
        
               | glouwbug wrote:
               | CTL just copy pastes a bunch of code via an include for
               | each new type. The following two tidbits are basically
               | the same thing:
               | 
               | CTL                   #define P          #define T int
               | #include <vec.h>
               | 
               | STL                   #include <vector>         template
               | class std::vector<int>;
               | 
               | C++ with its STL is just dramatically slower at compiling
               | it all. C loves to chew through its basic syntax and O(1)
               | lookup since every symbol is essentially unique (take
               | that C++ and your function overloading!)
        
             | eps wrote:
             | Intrusive containers are a way more natural fit for a C
             | codebase. They are also a superior choice for C++ code. The
             | one and only plus of STL containers is that they come
             | standard.
        
       | wudangmonk wrote:
       | If you want to use metaprogramming in C you are better off doing
       | the parsing/tokenizing yourself and creating your own macros than
       | trying to use the C preprocessor, its a lot less work.
        
         | bruce343434 wrote:
         | So basically create your own language + compiler that compiles
         | to C?
        
           | auxym wrote:
           | Or use Nim, which compiles to C :)
        
             | bruce343434 wrote:
             | To each their own :)
        
           | wudangmonk wrote:
           | Yes, its less work
        
         | ludocode wrote:
         | But then your code can't be used by anyone without your
         | preprocessor. There is a lot of value in plain C
         | metaprogramming because it can be compiled with an ordinary C
         | compiler.
         | 
         | You can, however, use a script to generate some of the
         | preprocessor boilerplate while still having the templates
         | configurable and instantiable with an ordinary C compiler. This
         | is how my metaprogramming library Pottery works:
         | 
         | https://github.com/ludocode/pottery
         | 
         | It uses #include for templates rather than code block macros,
         | something the article doesn't really go into. It's more
         | powerful this way and the templates are far more readable;
         | aside from the generated metaprogramming boilerplate, the
         | templated code looks like (and preprocesses to) ordinary C.
        
       | dmateos wrote:
       | Your scientists were so preoccupied with whether or not they
       | could, they didn't stop to think if they should.
        
       | veltas wrote:
       | If you introduce stuff like this into C it's major code smell. If
       | I see a 'cool macro to do a custom loop' in code I immediately
       | have to go look up what it does, and if it's as complicated as
       | this I'm going to want to read it all to make sure it's actually
       | right, I'll probably rediscover all the caveats he has at the end
       | of the article, and I'll wonder what the original programmer was
       | smoking.
        
         | pwdisswordfish8 wrote:
         | Indeed, better to just use C++.
        
           | veltas wrote:
           | So I can implement code smell without ever leaving the
           | comfort of C++? I've seen much scarier footguns in C++ than
           | I've ever seen done in the C preprocessor.
        
         | jacoblambda wrote:
         | I think what OP did was taking it a bit far but xacros
         | definitely have their place in C. Most notably they are
         | extremely useful for instantiating hardware interfaces that
         | often come with large amounts of boilerplate.
         | 
         | I've also found use in them in combination with `_Generic` for
         | implementing generic containers/data structures. Of course I
         | don't use these all the time by any means but if I'm going to
         | be using a complex data structure I might as well just use an
         | xacro to do a glorified copy-paste for the structs and
         | accessors. It's all type safe, doesn't make the code any less
         | readable IMHO, and it's surprisingly very debugger friendly.
         | 
         | The xacros used for this are all together only about 10 lines
         | of code but they've saved me countless hours of work/headache
         | over the years and I've never once seen them blow up in a way
         | that isn't immediately diagnosable and fixable.
         | 
         | I understand that macros are by no means to be used everywhere
         | but I do find that macros/xacros provide an incredible amount
         | of utility when putting together "library" or "HAL" code where
         | there's a well defined interface but the internals can largely
         | be hidden from the user/developer.
         | 
         | Of course I'd generally just prefer to use C++ but when that's
         | not an option or would add undue friction, I find macros/xacros
         | to be a useful tool for a developer.
        
           | veltas wrote:
           | I don't see any mention of xacros in the article.
        
       | toomanyducks wrote:
       | A while back I saw someone implement pattrn matching over
       | Rust/Haskell-like algebraic data types with macros in C99. Think
       | it was called something like Datatype99
        
         | Zababa wrote:
         | Here's a link: https://github.com/Hirrolot/datatype99
        
       ___________________________________________________________________
       (page generated 2021-07-10 23:01 UTC)