How in the world to C people cope with the lack of generics or higher-order anything.

"There's 5 types, and they go from one type to another type. That's 5 x 5 combinations with no repetitions, guess I'm just gonna add that. Then there's 3 error handlers, so you need to do 5 x 5 x 3. And then there's a few sub-genres, so that's 3 x 3 x 3 to add on,"

Maybe this is why all the C interfaces are untyped and unsafe. Doing it any other way is basically like loading up a combinatoric shotgun and flipping it around to point at your own chest.

@thephd I'm currently implementing a C interface, and the amount of const_cast I need...
@thephd What's more astonishing to me is that Rob Pike decided not to fix this problem when he made Go, making source generation (not even structured! it's string interpolation!) the idiomatic workaround.
@thephd I have Opinions on this
@fay59 I would like to hear your Opinions, someday. (Whenever, really, you feel like Divulging them.)

@thephd
This is absolutely why all C interfaces are untyped and unverifiable. For an entirely separate rant to have some other time, at least for pointers to single objects (as opposed to pointers into arrays), that tends to not be terribly unsafe in practice, though.

There's a famous quote in French: "ce qui se conçoit bien s'énonce clairement, et les mots pour le dire viennent aisément" (roughly: "when you understand something clearly, putting it into words comes naturally"). The French hold their language in high esteem, so it's used as a way to say that if you don't have the words to describe something, you should work on your understanding of that thing. This quote is weirdly relevant to programming languages, because often people understand concepts clearly, but they don't have the words to explain them to a machine–because the words don't exist. This is a failing of the programming language, not a failing of their understanding!

@thephd C in particular is very guilty of not having the right words to express useful ideas. To most people who like C despite there being alternatives, the reason I've come across the most is that they like languages that have a small number of primitives. This is never how it's phrased to me, but the best way I can synthesize it is that they perceive that each project has a budget of "understanding points" and they want to spend as much of that budget on project-specific knowledge and as little as possible on language knowledge. (I think that it's a flawed vision of "understanding points" because language understanding carries over.)
@thephd There's a niche for languages that aren't especially expressive but that don't use a lot of "understanding points". People love (or loved) ActionScript, JavaScript, Lua, C, Python 2 for those reasons. Pre-generics Java would have been in that category if it didn't have the most try-hard standard library in the world. For those people, not having generics is a feature. The unsafe is not a feature but it comes with the land (and in many cases, they would be OK with a runtime check, but that option doesn't exist broadly today).
@thephd I'm in camp "strongly-typed languages with generics and higher-order everything" because I think it's currently true that we have a pick-two situation for "small language, safe language, fast language" and the one I'm the most OK losing is "small language". Obviously, when your only option for "small, fast" is also unsafe, you have problems. I don't know if there's any obvious solution to that, but in general I think that PL people's interest in "small, safe" languages is way below what engineers' interest is.
@fay59 @thephd
From what I've seen in PL research is that small and safe with a good higher order type system also turns out to be fast because you can lower to an IR that optimizes well.
That the IR is unsafe is no more relevant than the von Neumann architecture being unsafe.

@fay59 @thephd "simplicity" is clearly either subjective or at least perceived subjectively

can't imagine working without static but generic types and somehow feeling it would result in thinking _less_ about wrangling the implementation details

@fay59 @thephd While I would say your description of "understanding points" is fairly accurate, I do not feel that C lacks words to express things. Quite the opposite: I find it far easier to express my ideas in C than in other languages. It may sometimes require more words in C than in other languages, because you have to work your way up from smaller low-level parts, but somehow that makes it easier for me than a high-level feature that then may not fit exactly to the idea I want to express.
@uecker @thephd what “our side” means when we say XYZ is easier to express in other languages is not always that it’s easier to write (although sometimes it is), but more that once you’ve written it, the mere fact that it builds is a proof that your program is free of many classes of mistakes.
@fay59 @thephd Not sure what "your side" is, but I am a bit confused. So by "easier to express" you mean "provable safe"? But this is does not seen to be the same thing and I would say a simple languages also helps makes things easier to prove. In terms how my own C code is structured, it would be relatively easy to prove certain properties. If you say a type system should make this explicit, I would agree and there languages that do this better than C (but certainly not C++).
@fay59 @thephd BTW: I am also a fan of higher-order type systems and I think we should add one to C! One with parametric polymorphism and dependent types! I think the result would be a language that is fast, small, and safe.
@fay59 @thephd This is a pretty fundamental thing with software engineering. The thing a software engineer should do is teach the computer about the concepts, the nouns and the verbs, of the subject matter, and only then write down what it is should happen to it.

@thephd When I first learned the sockets API, I was really confused at the generic socket and size to cast the first field of the struct.

I don't know if that is worse or better than void* (although I do think its nifty...)?

@thephd

@yosh and I are currently asking the Rust community the same questions around

`map`, `try_map`, `async_map`, `async_try_map`, `const_map`, `const_try_map` (thankfully there's no need for `async_const_map` or `async_const_try_map`)

And similar fun things (`get` and `get_mut` anyone?).

@oli @thephd @yosh *Haskell stans smirking smugly* 😅
@evntdrvn @thephd @yosh yea 😆 we're aware. But monads are probably a case of "the cure is worse than the disease" for Rust

@oli @thephd @yosh oh I totally get it, I was just joking :)

It reminds me of the discussions and decisions that @dsyme has made around user requests for typeclasses/HKTs in F#, and maintaining the spirit/essence/focus of a language—in that case, pragmatism rather than “category theory elegance/expressiveness above all else”
See e.g. this summary comment they made https://github.com/fsharp/fslang-suggestions/issues/243#issuecomment-916079347

Support type classes or implicits · Issue #243 · fsharp/fslang-suggestions

NOTE: Current response by @dsyme is here: #243 (comment) Submitted by exercitus vir on 4/12/2014 12:00:00 AM 392 votes on UserVoice prior to migration (Updated the suggestion to "type classes or im...

GitHub

@thephd
typedef struct {
void *data;
size_t len;
} list_t;
void list_add(list_t l, void *i);

#define DECLARE_LIST(t) \
typedef struct { \
t *data; \
size_t len; \
} t ## _list_t; \
inline static void t ## _list_add(t ## _list_t *l, t *i) { \
list_add((list_t)* l, (void*) i); \
}

@thephd Mostly by not over-engineering things.

@thephd

Three points:

0. a bunch of #define TYPE's that go with a discriminant union

1. a completely MACRO based single- or double- linked list that is used to chain all instances of the types

2. a bunch of functions that work on the pointer to the type (aggregate type usually) mutating it from one state to another.

all of this physically placed in a "single translation unit" with typedef'd pointers and 'static' storage class liberally used to control visibility.

easy to reason and works.

@saifi @thephd
"Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of CommonLisp."

@Sdowney @thephd

+1

David Drysdale and Chris Kohlepp discuss the same perspective such as you mention at length.

what i highlighted is how it is typically done (in plenty of C and also C++ code) in code that we still need to maintain.

many abstractions in C++ when two-levels deep become difficult to reason.

@Sdowney Btw, thanks for the useful github summaries that you publish for every version of C++.