4 ms·
Loose typing strikes again. I understand the temptation of "Let's just use an int return type, that way later on we can easily let them indicate different flav
by akoboldfrying 2y ago
Loose typing strikes again.
I understand the temptation of "Let's just use an int return type, that way later on we can easily let them indicate different flavours of error if we want". But then you leave yourself open to this.
The full-BDSM approach is for every component Foo that works with callbacks like this to define its own FooResult type with no automatic type conversions to it. In C, enum suffices, though a determined idiot can just cast to override; using FooResult as defined below makes it harder to accidentally do the wrong thing:
enum FooResultImpl { FOO_SUCCESS_IMPL, FOO_FAILURE_IMPL };
struct FooResult {
enum FooResultImpl USE_A_CONVERSION_FUNCTION_INSTEAD_OF_ACCESSING_THIS_DIRECTLY;
} FOO_SUCCESS = { FOO_SUCCESS_IMPL }, FOO_FAILURE = { FOO_FAILURE_IMPL };
(Yes, it's still possible to get an erroneous value in there at initialisation time without having to type out "USE_A_CONV..." -- but this is C, you can only do so much. You can't even prevent a FooResult variable from containing uninitialised garbage...)
- emn13 2y agoIs the advantage over an enum not kind of small? We're seeing bugs here because people tried to do the right thing but the tooling has absolutely no way of helping anybody to do that. Simply preventing accidental mistakes would prevent these. Adding complexity to make it harder (though never impossible) for consumers to misuse the API in a complex way seems like it's potentially going to far. Then again, it's been years since I used this kind of C, so maybe my instincts are rusty here (no rust-pun intended!)
- akoboldfrying 2y agoYou're right, this may be overkill. OTOH, casting between integer types in C can (unfortunately) feel like clicking away confirmation dialog boxes -- something too readily done without full understanding ("Oh, it's always just 1 or 0, of course it will fit in the target type [so no need to think further]"). While it's annoying boilerplate for the Foo component to have to write, I don't think clients of Foo see much additional complexity. They can still write "return FOO_SUCCESS;", etc.
- magicalhippo 2y agoI kinda like the way Boost did error_code[1], which got incorporated into C++11[2]. Essentially you got a generic error_code struct which has two members, an int to hold a given error value or zero if there's no error, and a reference to an error category which helps interpret the error value. Effectively the error category is an interface, so in C terms it would be a reference to an error_category struct filled with function pointers. There's then some machinery which allows you to compare specific error codes to generic error conditions like "file not found", abstracting away the specifics of the error code. It's not problem free[3], but I've used this pattern in languages like Pascal and felt it worked well for me. [1]: https://www.boost.org/doc/libs/1_82_0/libs/system/doc/html/system.html https://www.boost.org/doc/libs/1_82_0/libs/system/doc/html/s... [2]: https://en.cppreference.com/w/cpp/header/system_error https://en.cppreference.com/w/cpp/header/system_error [3]: https://akrzemi1.wordpress.com/2017/10/14/error-codes-some-clarifications/ https://akrzemi1.wordpress.com/2017/10/14/error-codes-some-c...
- alfiedotwtf 2y agoYes, a “Sum” type in Type Theory
- magicalhippo 2y agoWell it's more like a dynamically defined sum type, no? There's also the scaffolding around it, like the way error codes compare for equivalence[1] against error conditions in a symmetric way[2]. The result is you can easily add new a domain-specific error category, and error codes using your new category can be fed to existing code and they'll do something sensible without further modification. Your code with the new category could even be loaded at runtime[3]. Not something you can do with plain sum types, ie tagged unions in C. At least as far as I know, though I'm no expert. [1]: https://www.boost.org/doc/libs/1_82_0/libs/system/doc/html/system.html#usage_testing_for_specific_error_conditions https://www.boost.org/doc/libs/1_82_0/libs/system/doc/html/s... [2]: https://www.boost.org/doc/libs/1_82_0/libs/system/doc/html/system.html#ref_comparisons_2 https://www.boost.org/doc/libs/1_82_0/libs/system/doc/html/s... [3]: though there might be dragons, see my previous reference