←back to thread

218 points signa11 | 1 comments | | HN request time: 0s | source
Show context
throwaway7894 ◴[] No.43681266[source]
As someone who has a file with similar hacks, I will say this: I am not a C++ fan, but if you find yourself writing C code where you simulate methods via structs with function pointers often, just use C++ as a basic "C with classes" at that point. You want methods anyway, you have to go through a pointer dereference to call the function, it's just not worth the code weirdness. If you have the grit to use structs with function pointers everywhere, you have the grit to stick to the simpler subset of C++.
replies(5): >>43683169 #>>43683849 #>>43684044 #>>43701516 #>>43703558 #
unclad5968 ◴[] No.43683849[source]
I'm torn. The step from C to any c++ is big. Now if you want anybody to be able to use your code they need to be using c++ or you have to provide a C api anyway. On the other hand, manually implementing vtables is annoying. Ive been sticking to pure C and haven't been bothered enough to go back to any c++ yet (about 6 months on my current project). I mostly only miss templated containers so far.
replies(1): >>43701734 #
ryao ◴[] No.43701734[source]
It is more annoying to want to implement an optional function in a class and then have no simple way to check if that optional function is implemented in the object without, having to edit code that guards the call sites every time you add a derived class that implements it, or having to implement your own way of querying the object to know if it is supported.
replies(2): >>43701974 #>>43702572 #
unclad5968 ◴[] No.43701974[source]
I've never come across a situation where I wanted to do this. What would be a use case for optional class functions?
replies(1): >>43702373 #
ryao ◴[] No.43702373[source]
Well, it would not be a class in that case, but a use case would be anything that is modular where you want to support a new function, but do not require all of your implementors to use it. The best example of this is the VFS. Here is documentation for the Linux VFS:

https://www.kernel.org/doc/html/latest/filesystems/vfs.html

The vast majority of the function pointers in those structures are optional (even if not explicitly stated). To give a few common sense examples:

  * If your filesystem does not support extended attributes, you would not implement .listxattr and instead set it to NULL.
  * There are multiple ways of implementing read and write in file_operations. You have the basic read and write operations, and more efficient variants. You don’t need to implement the more efficient variants if you don’t want to implement them.
  * The .bmap call is used to find out how the filesystem stores a file on a block device, which used to be used by the syslinux (and might still be). This obviously is incompatible with NFS (or any multidisk filesystem like ZFS) so it absolutely must be optional.
Then there are other options, like not supporting mmap, or not supporting creation/removal of subdirectories. That sounds absurd, but some FUSE filesystems, particularly those exporting a program’s statistics, don’t bother with either of those since they are not needed. I do not believe Linux sysfs allows users to make directories either.

I could continue, but this gives a few examples of why you might want to have optional functionality in a class-like interface.

By the way, I mentioned setting things you do not implement to NULL. This is done simply by not specifying them when using the structure initializer syntax. The compiler will zero unspecified members.

replies(1): >>43703787 #
pjmlp ◴[] No.43703787[source]
Nothing prevents implement something like that in C++, it is still C++ code.

If you want to make something fancy, templates, if constexpr requires func-to-call, call func.

replies(3): >>43704295 #>>43704296 #>>43704299 #
1. ◴[] No.43704295[source]