struct dict dict_driver_ldap = {
.name = "ldap",
.v = {
.init = ldap_dict_init,
.deinit = ldap_dict_deinit,
.wait = ldap_dict_wait,
.lookup = ldap_dict_lookup,
.lookup_async = ldap_dict_lookup_async,
.switch_ioloop = ldap_dict_switch_ioloop,
}
};
defines the virtual function table for the LDAP module, and any other subsystem that looks things up via the abstract dict interface can consequently be configured to use the ldap service without concrete knowledge of it.(those interested in a deeper dive might start at https://github.com/dovecot/core/blob/main/src/lib-dict/dict-...)
I remember being impressed by this approach, so I shamelessly copied it for my programming game: https://github.com/dividuum/infon/blob/master/renderer.h :)
ffmpeg -i input.wav -filter_complex " [0:a]asplit=2[a1][a2]; [a1]lowpass=f=500[a1_low]; [a2]highpass=f=500[a2_high]; [a1_low]volume=0.5[a1_low_vol]; [a2_high]volume=1.5[a2_high_vol]; [a1_low_vol][a2_high_vol]amix=inputs=2[a_mixed]; [a_mixed]aecho=0.8:0.9:1000:0.3[a_reverb] " -map "[a_reverb]" output.wav
That said, keeping those interfaces clean and consistent as the codebase grows (and ages) takes some real dedication.
Also recently joined the mailing lists and it’s been awesome to get a step closer to the pulse of the project. I recommend if you want to casually get more exposure to the breadth of the project.
I'm surprised that this article never mentioned the term.
C++ programmers will know this pattern from the `virtual` keyword.
- instead of setting the same function pointers on structs over and over again, point to a shared (singleton) struct named "vtable" which keeps track of all function pointers for this "type" of structs
- create a factory function that allocates memory for the struct, initializes fields ("vtable" included), let's call it a "constructor"
- make sure all function signatures in the shared struct start with a pointer to the original struct as the first parameter, a good name for this argument would be "this"
- encode parameter types in the function name to support overloading, e.g. "func1_int_int"
- call functions in the form of "obj->vtable->func1_int_int(obj, param1, param2)"
[1]: https://learn.microsoft.com/en-us/windows/win32/com/com-tech...
[2]: https://www.codeproject.com/Articles/13601/COM-in-plain-C
No, that is essentially what Linux does in this article (and by the looks of it also ffmpeg).
struct file does not have a bunch of pointers to functions, it has a pointer to a struct file_operations, and that is set to a (usually / always?) const global struct defined by a filesystem.
As you can see, the function types of the pointers in that file_operations struct take a struct file pointer as the first argument. This is not a hard and fast rule in Linux, arguments even to such ops structures are normally added as required not just-in-case (in part because ABI stability is not a high priority). Also the name is not mangled like that because it would be silly. But otherwise that's what these are, a "real" vtable.
Surely this kind of thing came before C++ or the name vtable? The Unix V4 source code contains a pointers to functions (one in file name lookup code, even) (though not in a struct but passed as an argument). "Object oriented" languages and techniques must have first congealed out of existing practices with earlier languages, you would think.
The Power of Interoperability: Why Objects Are Inevitable
This paragraph completely derailed me — I’m not familiar with golang, but `interface` in Java is like `@protocol` in Objective-C — it defines an interface without an implementation for the class to implement, decoupling it entirely from the implementation. Seems to be exactly the same thing?
Manifold is a very interesting project that adds a lot of useful features to Java (operator overloading, extension classes, and a whole bunch more). I don't know if it's smart to use it in production code because you basically go from writing Java to writing Manifold, but I still think it's a fun project to experiment with.
1: https://github.com/SpongePowered/Mixin/wiki/Introduction-to-...
Go can't declare adherence up front, and in my view that’s a problem. Most of the time, explicitly stating your intent is best, for both humans reading the code and tools analyzing it. That said, structural typing has its moments, like when you need type-safe bridging without extra boilerplate.
Which makes a million times more sense to me, because realistically when do you ever have a structure that usefully implements an interface without being aware of it?? The common use-case is to implement an existing interface (in which case might as well enforce adherence to the interface at declaration point), not to plug an implementation into an unrelated functionality that happens to expect the right interface.
A signature declaration resembled an abstract base class. The target class did not have to inherit the signature: just have functions with matching names and types.
The user of the class could cast a pointer to an instance of the class to a pointer to a compatible signature. Code not knowing anything about the class could indirectly call all the functions through the signature pointer.
Transitively, it most definitely uses OO techniques. Furthermore, by having such a clean C ffi (in both directions) it allows for the weaving of the Lua based OO techniques back into C code.
https://stackoverflow.com/questions/15832301/understanding-c...
*int (*encode)(*int);
Why not compile your snippets? Heads up to the author.Benno Rice gave a fantastic talk a few years ago called "What UNIX Cost Us," which he starts off by showing how to write some USB device code in macOS, Windows, and Linux. It only takes a few minutes to demonstrate how pretending that everything is a file can be a pretty poor abstraction, and result in far more confusing code, which is why everyone ends up using libusb instead of sysfs.
"Everything is a file" is not a bad abstraction for some things. It feels like Linux went the route of a golden hammer here.
The specific reason I mentioned it was because his initial example was about how much more ceremony and boilerplate is needed when you need to pretend that USB interfaces are actually magic files and directories.
int (func)().
Maybe you meant: int * (*func)(void)?
Don't mean to be pedantic. Just wanted to point it out so you can fix it.
Other than that, yeah doing by hand what C++ and Objective-C do automatically.
Secondly, Apple and Microsoft, do just fine with Objective-C and C++ for their video codecs, without having to manually implement OOP in C.
Also, this is a nice way to get the damn banana without getting lost in the jungle.