12 ms·
Polymorphic Types in C [pdf]
- vkazanov 3y agoWow, suggesting polymorphic types to WG14 is... brave!
- illegalmemory 3y agoI had worked on something similar around 11-12 years back ( no way close to perfect or of any use :) ) https://github.com/nautical/CBullet https://github.com/nautical/CBullet Basically you can do something like this in c : var value; value = data(100); // or value = data(0, 2, 3, 4, 5, 6);
- pjmlp 3y agoThe answer to most post-C89 features could be just use C++, but yeah, changing human nature is a lost fight.
- flykespice 3y agoWhat about Ziglang?
- pjmlp 3y agoIn a way, Zig to me is Modula-2 with a revamped syntax for C minded folks, with a nice meta-programming story. In terms of language features. Personally I am not a big fan, because it doesn't have a good story for use-after-free (other than adopting similar analyser tooling like C derived languages), if I want to type @ all over the place I can use Objective-C, and the community doesn't seem very keen in supporting binary library distribution. That is me, we don't have to like all the same things. Even with UAF caveat, it still better than plain old C. Personally I find Odin more appealing than Zig.
- j16sdiz 3y agoC++ is somewhat bloat. We need a "C++ lite". We do this by moving features from C++ to C, bit-by-bits, until C become bloated.
- pjmlp 3y agoC would do better improving what matters, the lack of safe enumerations, strings and arrays, but even that they fail to copy from C++.
- lebubule 3y agoYes, please better support for arrays, mainly multidimensional. Fortran is good for that. With good arrays I think that strings comes naturally.
- uecker 3y agoWhat is wrong with multi-dimensional arrays in C? It works far better than in C++: void foo(int X, int Y) { double a[X][Y]; .. } In fact, this is one reason I switched away from C++, because arrays are so bad in C++.
- pjmlp 3y agoThat is a CVE waiting to be exploited.
- uecker 3y agoNo.
- pjmlp 3y agoIt definitely is, given a nice combination of parameter values, stack sizes and careless programming.
- uecker 3y agoIt is not more unsafe than fixed-sized arrays on the stack and stack clash protection (which you need anyway) protects against this. Also if you compare with C++ and use std::vector, surprise, a CVE about to happen: https://godbolt.org/z/cTG71aTsf https://godbolt.org/z/cTG71aTsf (yes, one can activate library assertions, but still - by default - unsafe)
- vkazanov 3y agoMany in this industry dislike C++'s approach to language design: "let's add everything and see what sticks".
- pjmlp 3y agoC is just the same, it just happens that not many people feel like showing up on WG14 meetings and push for their proposals. Showing up at WG21 is much more appealing to most folks. Maybe compare how C23 compares to C89, and future roadmap.
- flohofwoe 3y ago> Showing up at WG21 is much more appealing to most folks. ...and let's just hope it stays that way ;)
- flohofwoe 3y agoC++ has added more new design warts on top of C than C ever had though (which means that C++ is now caught in an infinite cycle of trying to fix warts it had introduced itself a couple of years ago). At least in C there's a possibility to learn from C++'s mistakes, and only integrate the 'good parts' (and the C++ template system certainly isn't one of those good parts).
- pjmlp 3y agoUnfortunely doesn't look like it is happening any time soon.
- logicprog 3y agoYeah, that would be the ideal — take just the simplest, cleanest version of C++'s good parts and integrated them. But lile the sibling post said, that's not what they're doing. Instead they're designing their own new versions of each feature that they add, and because it seems they're not willing to fully commit to new features or changing the language much, the features are always weirder with more gotchas and less baked than thr C++ versions. It isn't so bad right now because the language is overall much smaller, but if they eventually grow to anything close to the size of C++ (and C++ isn't even that big of a language anymore compared to other modern languages) it'll actually be way worse.
- uecker 3y agoHaving switched from C++ to C, I think C is a lot less weird than C++. But I also observed that C++ programmers usually do not "get" C (but think they do, because "it is just a subset") and often think some parts are weird simply because they are different. In any case, if you need a clean subset of C++ (but nobody I have met really agreed about what this is) nobody is stopping you from defining one.
- logicprog 3y ago> Having switched from C++ to C, I think C is a lot less weird than C++. Overall? Without a doubt. But these specific features they've been adding are implemented very unnecessarily strangely just to avoid fully committing to them, so that they end up in this design space where they may not be weirder than the full Lovecraftian horror of the equivalent C++ feature, but they are much weirder than the ideal/abstract concept of the equivalent C++ feature, which is what I wish they would have pulled in. Like, looking at this proposal, it isn't clear to me at all how the compiler is actually compiling or the runtime is executing these polymorphic function calls at all, in cases where they don't just collapse to void*. And it isn't clear to me how exactly type scoping and substitution works either. Whereas in concept at least templates are crystal clear and also easy to expand to do much more advanced macro-less metaprogramming, like D does. > and often think some parts are weird simply because they are different. I have way more experience with C than C++, but I'm usually a Rust programmer which works more like C++ so maybe that's where my bias is, but I really think this implementation is unnecessarily weird in general too — I've used a lot of languages.
- crabbone 3y agoI've been somewhat successful to use Ada instead. It has a lot of inconveniences of its own, but compared to C++ it's a language where it's hard to get things to work in any way, but once you get them to work, they are likely to do what you want, whereas in C++ it's easy to get things to compile, but then heaven only knows what that code will do. Also, Ada has a very decent interop with C. To the point that w/o any prior experience, I needed to use some functions from SQLite that weren't already exposed through Ada, and it was a pretty smooth sailing: very little "glue" code, all code that connected C and Ada was written in Ada.
- pjmlp 3y agoAda would be even better, unfortunely it is tainted by its past, and not an easy sell for most folks.
- tonyedgecombe 3y agoMy guess is this is what most people do. The few remaining holdouts are busy turning C into something that isn't C because they don't like things that aren't C.
- kitd 3y agoThere's libcello if you want to stay in C https://www.libcello.org/ https://www.libcello.org/
- synergy20 3y agowhich is inactive and the author has no intention to evolve it I think
- deleted 3y ago[deleted]
- vbtemp 3y agoI wish I had more than one upvote to give - what you just wrote is the truth of the matter.
- pgen 3y agoGreat, but I hate these leading underscores.
- injuly 3y agoIt's for backwards compatibility of C compilers (and lack of proper namespaces). All identifiers starting with an underscore are reserved for use by compiler intrinsics and such. Although most compilers don't complain if your variable names start with a leading underscore, it is recommended to not have such identifiers in your code.
- vkazanov 3y agoThey will probably come with macro-based aliases, the same way they did it elsewhere.
- Gibbon1 3y agoI feel increasingly annoyed with the idea that C can never have new keywords. As if that's some sort of huge problem with existing code bases.
- flohofwoe 3y agoThis is so that the new keywords don't collide with existing code (the combination of underscore followed by a capital letter is reserved). For instance until C23, 'bool' was actually called '_Bool' internally. Just as with stdbool.h before, there could be a stdlib header which wraps those internal names into something more human-friendly.
- uecker 3y agoMe too.
- injuly 3y agoPolymorphic types are certainly useful, and I wish C had a better way to go about it, but this proposal feels like an odd patch to C's type system. Especially this part: ``` Using a run-time value of type _Type T in _Var(T) can be allowed in general (and is useful), but needs to be restricted to contexts where full type information is not required at compile-time. ``` Semantic rules that conditionally apply only in some contexts is a common tendency of the C++ standard that many C programmers often dislike.
- nxobject 3y agoHere is another way in which this is a little patch-like. The author observes that: (a) it is desired that _Var(T)* and void* be compatible; (b) however. pointers-to-T for different T are not guaranteed to be compatible in general, as a consequence, it is NOT guaranteed that _Var(T)* is compatible with T*, which is a theoretical wart worthy of C++. I can see it becoming especially annoying if you’re trying to introduce _Var(T) polymorphism into a code base that currently uses preprocessor macros that textually substitute types. Perhaps the better solution would be forgo giving void* any special status whatsoever. However, that means that this type of polymorphism can’t be implemented using void* as a polyfill.
- uecker 3y agoI don't think this is a deficiency, but an inherent property of powerful type systems. If you make them very expressive, then you can not have full type checking at compile time. On the other hand, if you restrict them so that you do full static type checking, than they are very limited.
- nxobject 3y agoIt's a natural limit – but it doesn't make it easy to figure out in advance when it is/isn't permissible to do what you want to do. (Now, if C had type inference...)
- uecker 3y agoI am not sure I agree. What is allowed by the typing rules should always be clear. What may not always be clear is whether you statically get an error during compilation or only a run-time error. But considering that we now randomly get silent miscompilation which may or may not cause a run-time problem, if you cast a void* to the wrong type, I think this is a clear improvement.
- lerno 3y agoThe `any*` fat pointer in C3 is a version of this: https://c3-lang.org/anyinterfaces/ https://c3-lang.org/anyinterfaces/ Once this is available the step to embedding some runtime type information isn't far.
- eddd-ddde 3y agoI did not know about C3. I love C because is what I first learn to program, the simplicity, the complete lack of magic. Looks like I will love C3 as well: > Avoid "big ideas".
- eps 3y agoClean, very nice.
- keyle 3y agoInteresting. And reading all the changes from C, it looks like what occasional C developers should always remind themselves when coming back to C. That's a useful list by itself.
- Gibbon1 3y agoLooks. >Q: Why does C3 require that types start with upper case but functions with lower case? Hard pass.
- eps 3y agoAs a (not so) minor point - It's worth keeping in mind that code aesthetics is an important aspect of C codebases. There's a lot of C code that is exclusively lowercase, sans the macros. So introducing keywords like _Type and _Var will serve to hinder their adoption, because it'd make the code that much more "ugly". Just like what happened with _Generic - a reasonable feature, bad keyword selection -> barely any field use.
- isomorphic- 3y agoThe C specification mandates that new keywords use _Keyword naming conventions to ensure backwards compatability by not overriding potentially existing identifiers in codebases. That is why the C specification has reserved identifiers that begin with an underscore and either an uppercase letter or another underscore. Typically, a <stdkeyword.h> header is included that contain macros to provide the lowercased variants. I.E., this is how _Bool was implemented; <stdbool.h> provides the lowercased `bool` variant.
- eps 3y agoC23 is scheduled to promote bool, alignof & co. to keywords, so the concern for using _Xxx keywords is recognized by the committee. They introduce _Xxx keywords, sometimes alias them to lowercase versions with macros and let this age. Then, some time after, they switch to the "primary spelling", which is how the lowercase versions are referred to. You can't easily lowercase _Type and _Var, so practically speaking it will take years before these features could be suitable for wide-spread adoption. Hence my original comment - given the friction, is it worth expanding the language this way at all then?
- lifthrasiir 3y ago_Bool etc. came with convenience macros defined from <stdbool.h> and so on, but _Generic never did, suggesting that the underscored version was meant to stay forever that way. (Otherwise it should have been named as something like _Generic_switch and later renamed to generic_switch...) Maybe _Type and _Var are similarily intended.
- Dwedit 3y agoYou can still use virtual function calls in plain C, you just do things the same way that C++ does things internally. Your first member of the struct is a Vtable, and you need to assign that member when you create the object. Your first parameter for the virtual method calls is a "this" pointer.
- binary132 3y agoSlight detail: there only needs to be one instance of the vtable per class, and objects of that type only need to contain a pointer to it.
- Dwedit 3y agoAnd you can also make the vtable `const` so it goes into the read-only data section.
- huhtenberg 3y agoBy the same argument we don't really need C to begin with, because things can still be coded in assembly. It all boils down to convenience of reducing boilerplate. As the meme goes - "You don't need sneakers to run, but they sure help."
- phkahler 3y agoAnd if I understand your point its that we should embrace higher level tools rather than trying to build abstractions in lower level tools. In that case OP should just use C++ rather than trying to build an abstraction into C. That going higher level is actually why C++ was created in the first place.
- huhtenberg 3y agoThe point was that if there's a certain coding pattern that can be accommodated by adding a new language feature, it is worth considering. The fact that it's readily doable with some effort in some other way is not an argument against it. C++ started as a reasonable extension to C, but now it's just something else (nor does it even want to be seen related to C now anyway). Extending C with something new, without rushing, is a perfectly fine idea.
- smcameron 3y agoIs it just me, or are disillusioned C++ refugees who've gone back to C now trying to wreck it a second time? Probably just me. Since the 80's, C++ served as an excellent decoy to absorb craziness and keep C sane.
- zabzonk 3y agoit is just you. why would anyone go back to C from C++? if you want to write C in C++, you can do that, with the advantages of stronger type checking.
- SV_BubbleTime 3y agoYou can use the C syntax in C++. But you are not using C, your compiler is still C++.
- zabzonk 3y agoyes the compiler is the same (for example gcc or msc) but why would you care?
- SV_BubbleTime 3y agoFirst off… GCC is not the compiler. It is the toolchain collection. Second, no, g++ does act identical to the c compiler component of GCC.
- burstmode 3y agoMany people, Especially sice C++ has become a playfield for CS language theorists, who invent more and more overcomplicated language "features" with little to no practical use.
- pjmlp 3y agoThat is still Haskell. Getting features into WG21 still requires some effort to get them through, regardless of what people in the outside think, and yeah I do agree it could get some more direction. C++ may seem to get everything dumpped into it, however any language nerd that feels like diving into what the history of languages with similar age (Python, Perl, Ada, C#, Java, F#, OCaml,...) have across all their versions, standard library, main interpreter/compilers, .... will find out those aren't much better either.
- sfpotter 3y agoWhat problem does this solve that isn’t superficial? I don’t see why it’s important to include.
- sigsev_251 3y agoGeneric libraries. There are programming domains in the embedded world where code reuse can shorten the development timeline in a significant way, which gives engineers more time to test and verify.
- sfpotter 3y agoExample? Why not just use C++?
- sigsev_251 3y agoBecause there are platforms with no, or really buggy C++ support.
- sfpotter 3y agoWhat is an example of an embedded systems project which truly benefits from a generic library in the way that you described?
- sigsev_251 3y agoAviation would be my personal experience. We have to implement services on the aircraft for structured communication support with the ground tower. Those would really benefit from something like that, since we wouldn't have to implement a backend for every project and we could simply reuse the whole library everywhere.
- sfpotter 3y agoI don’t see how generic programming (a la polymorphic types as presented) is the only or even the best solution to this problem.
- synergy20 3y agoIMHO, the C committee should just copy a subset from C++, in addition to having new features for free, you also make sure c and c++ are 100% compatible.
- up2isomorphism 3y agoThere is no point to make sure C/C++ 100% compatible and also you can not as of now.
- muragekibicho 3y agoI use C at my day job and our company works with ANSI C. I believe it's C89. I was curious to find out - who's using C23 in prod? Please let me know in the comments. I'm super curious!
- ptek 3y agoEmbedded developer or are you porting software? Is it C89 or gnuc89? gnuc89 is the one that allows // for single line comments, I don't know what other features gnuc89 adds over c89. I also call C89 ANSI C :) Are you guys using gcc or clang?
- muragekibicho 3y agoWe make file formats. It's all C and we work on the low-level FFmpeg C API and low-level jpeg & brotli apis. We use GCC. I didn't know there's C89 and gnuc89 lol
- kazinator 3y ago> The following for [sic] declaration [sic] are then all equivalent: int i; int *ip; typeof(i) *i; _Var(_Typeof(i)) *i; What? How are "int i" and "int *ip" equivalent? _Var(_Typeof(i)) ident strikes me as incredibly silly. The type value produced by _Typeof(i) should be directly usable as a declaration specifier, without requiring hoisting to a name. FFS, GNU C has had a sane typeof working for years. To bind a type to an identifier, we don't need a _Type type at all. typedef does this! I.e. not: _Type x = int; but typedef int x; Existing, decades-old typedef is how you bind an identifier to a compile-time type value. There is no need to do this via a _Type type specifer, which then forces us to move the type we want into the initializer. We use the typeof storage class specifier, which then lets us have the type we want as another specifier, and we don't need an initializer. This works in GNU C: int x; typedef typeof(x) tx; // same as typedef int tx; The problem of declared, named containers to capture type is long solved.