4 ms·
> This makes no sense to me. What about C makes it hard to use a good library? It doesn't have templates/generics.
by zrm 3y ago
> This makes no sense to me. What about C makes it hard to use a good library?
It doesn't have templates/generics.
- deleted 3y ago[deleted]
- kevin_thibedeau 3y agoC11 added (limited) generic support
- remexre 3y agoYou can't specialize a generic algorithm for specific operations and data structures; in C++ terms, it gives you overloading, not templates.
- kevin_thibedeau 3y agoIt gives generic programming. C++ templates aren't the only possible implementation.
- kaba0 3y agoSo where is a generic vector data structure written in plain C that is efficient (that is, doesn’t store pointers to elements).
- zrm 3y agoThey used "_Generic" as a keyword but it doesn't really do that. Suppose I need to define a copy assignment operator for the library's sort function to use. Is there a good way to overload it? Can the library know what the size of each element is based on its type without having to pass it in as a parameter? You can pass function pointers to the library, but that quickly becomes awful. /* sort for basic integer types */ void lib_sort_u8(uint8_t *a, size_t count); void lib_sort_i8(int8_t *a, size_t count); void lib_sort_u16(uint16_t *a, size_t count); void lib_sort_i16(int16_t *a, size_t count); void lib_sort_u32(uint32_t *a, size_t count); void lib_sort_i32(int32_t *a, size_t count); void lib_sort_u64(uint64_t *a, size_t count); void lib_sort_i64(int64_t *a, size_t count); /* specify a comparator */ void lib_sort_comp(void *start, size_t nmemb, size_t size, int (*compar), const void *, const void *)); /* specify a comparator and an assignment operator */ void lib_sort_assign_comp(void *start, size_t nmemb, size_t size, void (*assign)(void *, const void *), int (*compar)(const void *, const void *)); /* specify a comparator, an assignment operator, and ... */ Or, you get one function that takes all of the arguments and have to define and pass in a bunch of function pointers and type size parameters that are each an opportunity for bugs or UB in order to sort a simple array of integers. If my type needs a custom assignment operator, I need each library I use to take that as an argument. One expects the function pointer to take the arguments in the order (src, dst), another as (dst, src), a third specifies the return value as int instead of void, a fourth takes the source argument as "void *" instead of "const void *" in case you want to implement move semantics and a fifth doesn't support custom assignment operators at all. It's no surprise that people prefer to avoid this.
- acuozzo 3y agoThe lack of namespaces is of far greater consequence.
- Jorengarenar 3y agoLIBNAME_actual_function_name()
- acuozzo 3y agoAnnoyance #1: External symbols are expected to be unique within 31 characters according to the standard, so you're limited to a few namespace "levels", at most. curl_easy_option_by_name() is already up to 24 characters and there's only two "levels" in curl_easy_*. Annoyance #2: There's no formal registrar for LIBNAME. This isn't a big deal for popular libraries, but it's a pain having to keep a locally-modified copy of a less popular dependency just because it shares its name with another less popular dependency. Annoyance #3: LIBNAME_actual_function_name() is a pain to read and using either the preprocessor or static inlines to locally alias function names for the sake of readability is silly.
- Jorengarenar 3y ago@1: The limits are considered obsolete since C89 and implementations are encouraged to avoid them whenever possible. I think the same way we disregard non ASCII character sets, non two's complement encodings and similar, we are safe in assuming sane implementation being able to handle longer names. And being honest, if given implementation isn't capable of more than 31 significant characters, then it would have problems with namespaces too. @2: Agree, although I don't recall this ever happening to me. @3: Is it? How is libname::actual_function_name() much better? I actually like to use libname__actual_function_name(), as it further separates "namespace" from function name (unless we need compatibility with C++, as IIRC it reserves all double underscores, not only at the beginning).
- acuozzo 3y ago> @1: The limits are considered obsolete since C89 and implementations are encouraged to avoid them whenever possible. This is still the case in C11, Section 5.2.4.1. Did this change in the most recent standard? > @2: Agree, although I don't recall this ever happening to me. It happened to me once. I ran across a library from 1994 and another from the 2010s which shared a simple name like "libamc". I'll comb through my records later to figure out the actual name. > @3: Is it? How is libname::actual_function_name() much better? It's not, but I wasn't thinking of C++ specifically. (I don't know C++. I've somehow managed to avoid it in many years of writing C.) I was thinking more like the file-local namespace clobbering offered by Python e.g., from LIBNAME import actual_function_name.