Skip to content

Instantly share code, notes, and snippets.

View keebus's full-sized avatar

Massimo Tristano keebus

  • Epic Games
  • Amsterdam
View GitHub Profile
@keebus
keebus / local_opaque_object.c
Last active March 25, 2022 21:33
Local opaque object in C
// library.h -------------------------------------------------------------------
#define opaque(Type) Type; int $sizeof_##Type(void);
#define opaque_impl(Type) int $sizeof_##Type(void) { return sizeof(Type); }
#define local(Type) ((Type *)alloca($sizeof_##Type()))
// foo.h -----------------------------------------------------------------------
@keebus
keebus / cexceptions.md
Last active March 25, 2022 21:32
Exception-like code in C (gcc/clang)

Lightweight exceptions in C (with gcc/clang)

For fun I implemented a lightweight exception mechanism for C that allows writing transactional code. This is what it looks like:

int device_create(device_t **odevice)
{
	throwbase(-1); // makes this function "throwing" with a default return value of -1.

	device_t *device = malloc(sizeof *device);
	check(device); 
@keebus
keebus / opaque_class.md
Last active September 28, 2021 20:49
Opaque Class

Opaque Class

I believe C++ classes implement encapsulation extremely poorly as they require private variables and functions to be declared together with the public interface, clashing with C-style code modularization based on header files inclusion. To implement real incapsulation, we would like to only present the class public interface in its header, hiding all the other information. Unfortunately the canonical ways to achieve this in C++ are both flawed as they introduce unnecessary overhead.

  1. One is Pimpls for Private Implementations. They rely on forward declaring a private class that actually implements the public class functionalities and then only holding a pointer to this private class within the public class. This adds one level of indirection, as now a pointer to the public class does not point to the data iself but to a pointer to the data.
  2. Virtual interfaces are the other way, which is even worse than Pimpls as they add overhead to each member function call.

Although C does not

@keebus
keebus / dynamic_traits.md
Last active October 10, 2019 14:22
Dynamic traits

Dynamic Traits

During ordinary C++ development we ofter encounter the situation where we want to operate with similar objects through a common interface. C++ natively supports only one idiomatic way of implementing dynamic function dispatch, the _virtual_ keyword. The idiomatic, traditional OOP way to solve this problem in C++ is to declare pure-abstract classes, also called interfaces and implement them in other abstract or concrete classes in their declaration explicitly.

This solution has at least a couple of serious drawbacks:

  1. It introduces strong type coupling between the class that implements the interface and the interface itself. Specifically, the class needs to know in advance what interfaces it wants to implement. Although this is sometimes the case, it is not always the case, and more often this coupling is undesirable. Finally, C++ classes once declared cannot later on be opened, adding more implementations to interfaces. This means that you cannot, through standard C++, declare an
@keebus
keebus / finally.md
Last active August 13, 2020 07:39
Finally

Finally

One of C++'s strengths is automatic code invocation at scope-exit (aka RAII). The traditional idea behind RAII of having specialized types for every resource type with a custom destructor that frees it is good in theory but in practice comes with a lot of friction and thus boiler-plate and frustration for the developer, that now has to create a new type for every little rollback operation he wants to perform. The problem is exacerbated with C++11 move operators: making a small "smart" class that does some form of cleanup now requires even more boilerplate.

Fortunately there's a way to neatly work around this, and the idea comes from D's scope keyword or Go's defer. We want a mechanism that tells the compiler to invoke a snippet of inlined code at scope exit. Something like

// Acquire a resource
Resource* resource = AcquireResource();

// Then whatever happens, release the resource when it goes out of scope.