7 ms·
> C is the glue interface that connects all the different languages together. I wouldn't want to see anything new added to the language that complicates this li
by sirwhinesalot 5y ago
> C is the glue interface that connects all the different languages together. I wouldn't want to see anything new added to the language that complicates this lingua franca.
Indeed, this is one of the two things where C is still king, the other being running on weird hardware with specialized compilers.
That said, C is not a great glue language:
- Zero terminated strings are only used in C so every other language needs to do a copy to pass a string to C, even C++ (for string_view at least).
- A lack of fat pointers means that buffers need to pass their pointer and length separately, which is awkward, or use a custom struct which other languages will know nothing about.
- It has no standardized error handling mechanism to help with writing automatic wrappers on the other language endpoints.
- It has no modules or namespacing.
So while C will continue to be the glue language of the programming world, I wish it was just a bit better than what it is, would make language interoperability a lot nicer...
- _the_inflator 5y agoI agree with you. However, I think the real value of the language is that, despite flaws, it provides a reasonably consistent platform in this "glue" context. It better to have one imperfect language, than a dozen perfect.
- sirwhinesalot 5y agoI know "upvote" comments are frowned upon, but I just wanted to say I most certainly agree. I'm glad we ended up with such a language, even with all its flaws.
- pornel 5y agoI think it would be beneficial to create a better interoperable ABI description (one, not a dozen). Not in a form of a language header, but a data file that can be easily consumed by tools of any non-C language. 1. C headers are exceptionally annoying to correctly parse and interpret. You basically have to have a full C compiler, which is a PITA for a non-C tool. It's not just complexity of the C syntax, but dependency on system headers, implicit platform-specific type sizes and struct layouts, and an arbitrary web of ifdefs which may need to be generated by an arbitrary build system. Everything here resists automation, and if you get any details wrong, you won't know until you see memory corruption. 2. The common baseline between most programming languages has outgrown what C can express. Namespaces and other name mangling, unwinding, non-nullable types, slices, ownership/destructors, thread-safety annotations, etc. C++ has some of these features, but it solves none of the above problems, and only adds more complexity and its own compiler-specific behaviors.
- sirwhinesalot 5y agoIt has been attempted at least at the OS level. COM and the much improved WinRT are one example (WinRT relies heavily on metadata), the Objective-C runtime on Apple platforms is another (which instead accepts lots of dynamism). The problem is that OS vendors are the only ones with enough sway to force people to use these things, and even then just barely (the Rust WinRT support is developed by Microsoft themselves). The only entity with enough sway over every language in existence when it comes to supporting an ABI is, ironically, the C standards committee, because every language already talks C and needs to continue to do so.
- oconnor663 5y agoCould WASI grow into this role?
- skitter 5y agoWASI is an API, not a way of specifying APIs.
- throwawaylinux 5y ago> That said, C is not a great glue language: - Zero terminated strings are only used in C so every other language needs to do a copy to pass a string to C, even C++ (for string_view at least). I don't think that's what he's talking about. No matter what glue you had, you need to pass NUL terminated strings to C code that uses NUL terminated strings. The glue interface does not require any such thing though. > A lack of fat pointers means that buffers need to pass their pointer and length separately, which is awkward, or use a custom struct which other languages will know nothing about. Again passing things between two languages will always necessitate that. One language might have a different fat pointer implementation than another. And the nice thing about glue code is that it can be easily automatically generated calling wrappers so "awkward" does not come into it - you change one language's data types into another's. > - It has no standardized error handling mechanism to help with writing automatic wrappers on the other language endpoints. - It has no modules or namespacing. I don't see how this matters for the interface glue. You can define the error handling with it how you like. You put it in your language's namespaces and modules.
- sirwhinesalot 5y agoYour comment is assuming that language A knows about language B. That's one case, but not the usual one. Rather, languages like Rust/Zig/C++ and even C# and Java let you expose a C API such that other languages can understand the shared library as if it was written originally in C, because C is the only thing every other language talks. By necessity this involves using standard types available in C otherwise the other languages have nothing to go on, they'd just have a bunch of opaque types and no way to create them. If C had better builtin constructs, these "extern C" APIs could be much better semantically, such that automatically generating wrappers to this C API would result in safer, more efficient, and more ergonomic code in the host language.
- throwawaylinux 5y ago> Your comment is assuming that language A knows about language B. That's one case, but not the usual one. > Rather, languages like Rust/Zig/C++ and even C# and Java let you expose a C API such that other languages can understand the shared library as if it was written originally in C, because C is the only thing every other language talks. The C interface glue is not the problem here. You can write the library with a completely different language and using fat pointers, and simply adjust the calling convention at the C interface, and it can be called by a different language that uses fat pointers and everything can use fat pointers. The actual problem is you can't just say that your interface glue is going to have all these wonderful features and that therefore everything will magically work and use them. > By necessity this involves using standard types available in C otherwise the other languages have nothing to go on, they'd just have a bunch of opaque types and no way to create them. Using C interface glue does not require you to even write a line of C code let alone C types if your compiler knew how to call the APIs. > If C had better builtin constructs, these "extern C" APIs could be much better semantically, such that automatically generating wrappers to this C API would result in safer, more efficient, and more ergonomic code in the host language. Again there's no reason your language can not wrap those and expose your desired higher level semantics or features to your code on the other side of the wrapper layer.
- jstimpfle 5y ago> Zero terminated strings are only used in C so every other language needs to do a copy to pass a string to C, even C++ (for string_view at least). This is one of the most frequent complaints and I find it ridiculous. C has string literals that encode zero-terminated strings, but you don't have to rely on these zero terminators. There are a few awquard "string functions" in libc, most of which you should just ignore. Besides maybe the printf() family (which you probably wouldn't want to use for interoperability there isn't anything that requires zero-terminated strings. This language gives you memory to work with, and it's up to you how you want to achieve your goal. > A lack of fat pointers means that buffers need to pass their pointer and length separately, which is awkward, or use a custom struct which other languages will know nothing about. It could be considered a security problem that sizes have to be passed separately, but what I consider awkward is actually the slices approach: In general the count field in a "slice" is redundant data - think about parallel arrays, where with slices you need to synchronize the count information across all slices. Passing separate length is the correct approach from a normalization standpoint. > It has no standardized error handling mechanism to help with writing automatic wrappers on the other language endpoints. Similar to the point about slices, not including any notion of "errors" is the correct way of doing it. In general you don't want errors in a system, only data that you handle in an appropriate way. Also, returning what people usually consider errors is often a bad idea, as such error information should better be stored in a persistent handle or context struct. > It has no modules or namespacing. Not a problem, since there are names that you can already use for disambiguation. Namespaces only add more ways to identify the same object, which leads to ambiguity and/or hard to read and hard to grep code. (Namespaces encourage the use of not-fully-qualified identifiers - actually this is the only thing they really add, and apart from some metaprogramming tricks you can play I don't think it's a great addition).
- unionpivo 5y ago> This is one of the most frequent complaints and I find it ridiculous. C has string literals that encode zero-terminated strings, but you don't have to rely on these zero terminators. Just a quick question. Is there somewhat up-to-date guide, list, book, whatever of good best practices for C, or maybe small libs for simple string handling, and common pitfalls (checking for over/underflows etc.)?