[HN Gopher] C Object Oriented Programming (2014)
       ___________________________________________________________________
        
       C Object Oriented Programming (2014)
        
       Author : sergiogdr
       Score  : 36 points
       Date   : 2023-12-20 12:46 UTC (1 days ago)
        
 (HTM) web link (nullprogram.com)
 (TXT) w3m dump (nullprogram.com)
        
       | naitgacem wrote:
       | Excellent writeup and straight to the point. As the author
       | demonstrated one can get quite a lot of OOP constructs using C
       | primitives.
       | 
       | what seems to be impossible to implement (as least to me) was
       | something like interfaces, a way to decouple in a way such that
       | high level functions don't need to know about the low level
       | building blocks.
        
         | skribanto wrote:
         | You can approximate it by maintaining some kind of vtable, but
         | it can get messy, especially if you need to implement multiple
         | traits/interfaces.
        
         | pjmlp wrote:
         | We used to have books about it, and stuff like COM, SOM, CORBA
         | also support C, which is exactly what you're referring to.
         | 
         | Regarding books, here is one from 1993,
         | https://www.mclibre.org/descargar/docs/libros/ooc-ats.pdf
        
           | vkazanov wrote:
           | Classic..!
           | 
           | I wonder how it feels now, 20 years after reading it for the
           | first time. I remember how revelatory it felt.
        
         | miuramxciii wrote:
         | Yes, You can. The entire Linux device interface, to name just
         | one example, if full of interfaces. The way to accomplish this
         | is via pointer to functions, and to have it as an object, have
         | these pointer to functions grouped in a struct. GTK/Glib is
         | notably full of these interfaces too.
        
           | spaceywilly wrote:
           | Yup. In a past job I did a lot of work writing ALSA drivers
           | for custom souncards. The ALSA interface is a good example of
           | this. They provide an API app developers can use to do sound
           | stuff (change the volume, for example). In your sound card
           | driver you provide an implementation of the API to do
           | whatever changing the volume means for your particular
           | hardware (in my case sending an i2c message to a digital
           | potentiometer).
           | 
           | https://www.kernel.org/doc/html/v4.14/sound/kernel-
           | api/alsa-...
        
         | dboreham wrote:
         | Um, this is how software was built in the olden days. C++
         | literally began as "we could write a preprocessor to automate
         | the tricks everyone uses to implement polymorphism in C"
         | (CFront). And prior to that, the same tricks were used in
         | assembly language programming. So this article has recreated
         | the history of OOP, which was to create tooling to better
         | support programming techniques already widely used. It wasn't
         | some religion invented by the priests and sent forth on
         | tablets, although due to humans loving them some cult, it
         | became that eventually.
        
         | dceddia wrote:
         | One thing to look at is ffmpeg in its encoders and decoders. At
         | the bottom of the file there's a struct with pointers to
         | functions (among other things). Anything that wants to do
         | decoding can just call init(), decode(), close() on an AVCodec
         | and the internal functions do whatever they need to do. Here's
         | one from h264.c:                   AVCodec ff_h264_decoder = {
         | .name     = "h264",           .type     = AVMEDIA_TYPE_VIDEO,
         | .init     = ff_h264_decode_init,           .close    =
         | h264_decode_end,           .decode   = h264_decode_frame,
         | ... more fields ...         };
        
       | nanolith wrote:
       | One advantage to this approach is that there is less compiler
       | magic going on. I use a similar approach, but I prefer using type
       | safe upcasting or model checked downcasting via inline functions
       | or explicit references to base members, instead of direct C style
       | casting.
       | 
       | This also makes it easier to develop a uniform resource
       | management strategy with allocator abstraction. Being able to
       | easily switch between tuned bucket, pool, or bump allocation
       | strategies can do wonders for optimization.
       | 
       | It's possible to model check that downcasting is done correctly,
       | by adding support for performing type checks at analysis time. In
       | this case, a type variable is added to the base type that can be
       | compared before casting. Since this is an analysis only variable,
       | it can be wrapped in a macro so that it is eliminated during
       | normal compilation. Static assertions checked by the model
       | checker during analysis time may need to be refactored to extract
       | the type information as a proof obligation made by the caller.
       | This technique actually works quite well using open source model
       | checkers like CBMC.
       | 
       | Either way, some C OOP is not only useful to provide some
       | optimization knobs, but it's also quite useful for introducing
       | annotations that can help to formally verify C but that don't
       | actually incur any runtime overhead.
        
       | o11c wrote:
       | Hmm, I don't have much to disagree with for this link, unlike
       | many things from that site.
       | 
       | One minor point - the method implementations should _not_ be
       | `static`, so that you can support further subclassing and reuse
       | the base class implementations.
       | 
       | Note that to support both virtual and non-virtual method binding,
       | the dispatcher also needs to be exported (with the same
       | signature). This is already the case in the linked code but a
       | point isn't made of it; it can be tempting to abuse `inline` but
       | remember that is primarily about visibility [1].
       | 
       | It also doesn't mention how to implement `dynamic_cast`
       | (practically mandatory for multimethod-like things), which can be
       | quite tricky, especially in the multiple-inheritance case and/or
       | when you don't know all the subclasses ahead of time and/or when
       | you have classes used in across shared libraries. There are cases
       | where you really do need multiple vtables.
       | 
       | Virtual inheritance, despite its uses, is probably a mistake so
       | it's fine that it ignores that.
       | 
       | [1]: https://stackoverflow.com/a/51229603/1405588
        
       ___________________________________________________________________
       (page generated 2023-12-21 23:00 UTC)