The `any*` fat pointer in C3 is a version of this: https://c3-lang.org/anyinterfaces/ Once this is available the step to embedding some runtime type information isn't far.
Interesting. 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.
I 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:
Polymorphic 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.
I 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.
It'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...)
Here 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.
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.
The 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.
C23 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?
IMHO, 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.
It'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.
This 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.
You 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.
The problem with rolling your own virtual tables without compiler support is that devirtualization is generally not possible, even in fairly easy cases.
If by "devirtualization" you mean inlining the virtual method and associated optimizations, that can be done with If-else (checking which vtable it is), then explicitly calling the function. Failure to find a known method can proceed to calling the function pointer.
By 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."
And 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.
>Q: Why does C3 require that types start with upper case but functions with lower case?
Hard pass.
> Avoid "big ideas".
Basically you can do something like this in c :
var value;
value = data(100);
// or
value = data(0, 2, 3, 4, 5, 6);
``` 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.
(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.
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.
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.
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?
Just as with stdbool.h before, there could be a stdlib header which wraps those internal names into something more human-friendly.