I would have designed the feature like this: _Generic( , type1 : ( expr1 ), type2 : ( expr2 ), ... default : ( expr )) Here, the parentheses shown in this phrase pattern are required. The implementation would only parse and semantically analyze the expression of the matching type. For the others, the ( expr ) would be treated as a token sequence to be skipped, which has to contain valid tokens, and balancing parenthe…
Workarounds for C11 _Generic()
31–40 of 58 posts
Re: Workarounds for C11 _Generic()
#32The only reason I can imagine for this behaviour is that the compiler/standard writers did not want it. Maybe C just shouldn't include generics. Especially not as part of the macro layer.
Generics are fine. Its useful to have some introspection into the data that compiler has. Thats the whole point of macros in the first place. The behavior with _Generic is basically emergent behavior from implementation of macro processors. Macro replacements occur prior to actual compilation, so no compiler context exists for x, as such all code paths must be valid. Its much easier to require the programmer typecast…
How is it throwing an error like "invalid type argument of ‘->’" if there's no compiler context?
And why does an error like that get in the way of macro replacements?
(That might be the wrong message but the article says you at least get an equivalent.)
Re: Workarounds for C11 _Generic()
#33I would have designed the feature like this: _Generic( , type1 : ( expr1 ), type2 : ( expr2 ), ... default : ( expr )) Here, the parentheses shown in this phrase pattern are required. The implementation would only parse and semantically analyze the expression of the matching type. For the others, the ( expr ) would be treated as a token sequence to be skipped, which has to contain valid tokens, and balancing parenthe…
That would allow you to put syntactically invalid code into the expressions, but is that a useful feature? It's not very hard to have valid syntax in a situation like this. The main issue here is type enforcement.
It would solve the usability issues experienced by Simon Tatham, described in his article. For instance, if one of the clauses has x->foo, it wouldn't matter that the actual x argument in a given instance is char *, that cannot be dereferenced as x->foo.
It would be up to the programmer to test every one of the supported cases of their _Generic construct.
One way to avoid problems would be to include only cases that are used in your codebase. Before adding a new case, add a use* of your generic macro with the currently unsupported type. That should fail to build. Then, add the case. (TDD style).
The preprocessor's #ifdef allow syntactically invalid code. This is very useful; it lets you have conditional sections of code that are understood only by certain compilers due to using their extensions.
Arguments to preprocessor macros, if not planted into syntax, can be syntactic gibberish, but parentheses have to balance. You cannot invoke a macro as mac({(}) and such.
_Generic is meant to work with macros; it should have some macro-like forgiveness in it to make it as useful as possible.
In Common Lisp, the #+ and #- syntax for conditionally skipping forms is similarly defined as doing a minimal parsing for balancing parentheses and a few other details. This allows #+ to switch between implementation-specific code that includes implementation-specific read syntax that cannot be read by all implementations.
http://www.lispworks.com/documentation/lw51/CLHS/Body/02_dhq...
It works by binding *read-suppress* to true and then calling read to read the form.
Re: Workarounds for C11 _Generic()
#34Earlier quoted context omitted.
That would allow you to put syntactically invalid code into the expressions, but is that a useful feature? It's not very hard to have valid syntax in a situation like this. The main issue here is type enforcement.
> but is that a useful feature? It would solve the usability issues experienced by Simon Tatham, described in his article. For instance, if one of the clauses has x->foo, it wouldn't matter that the actual x argument in a given instance is char *, that cannot be dereferenced as x->foo. It would be up to the programmer to test every one of the supported cases of their _Generic construct. One way to avoid problems woul…
In a very overkill way, though. You can solve the issue in the article by parsing the expression but not doing anything with it. You don't need to allow invalid syntax for that problem.
So to be clear, I'm asking specifically about whether it's useful to allow invalid syntax inside _Generic. What does that allow in practical use, moreso than allowing valid syntax with invalid types/semantics?
Re: Workarounds for C11 _Generic()
#35Not directly related but does some c/c++ compiler implement a combination of flags that create a sort "c with templates" version of C ?
If C wanted a form of generics, it could likely do much better than templates. Concepts might've improved things, but I'm stuck on C++17 right now so I can't speak with experience.
Re: Workarounds for C11 _Generic()
#36The only reason I can imagine for this behaviour is that the compiler/standard writers did not want it. Maybe C just shouldn't include generics. Especially not as part of the macro layer.
As a member of the WG14 I can tell you that _Generic does cause a fair bit of issues and complications in the language, and as a user of C i think _Generic is bad, because it mostly useful for confusing users about what code does so, Yes C would be better off without _Generic. Please don't use it.
Re: Workarounds for C11 _Generic()
#37The only reason I can imagine for this behaviour is that the compiler/standard writers did not want it. Maybe C just shouldn't include generics. Especially not as part of the macro layer.
Generics are fine. Its useful to have some introspection into the data that compiler has. Thats the whole point of macros in the first place. The behavior with _Generic is basically emergent behavior from implementation of macro processors. Macro replacements occur prior to actual compilation, so no compiler context exists for x, as such all code paths must be valid. Its much easier to require the programmer typecast…
Re: Workarounds for C11 _Generic()
#38Earlier quoted context omitted.
That would be my advice too. What was the point of “You don’t pay for what you don’t use” if nobody’s going to use it?
There's no common C++ build system. That means (among other things) that there's no way to turn features you don't use into compile-time errors. There's no project configuration to select an allowed subset of features. All the difficulty goes onto the programmers, and in a multi-person project into the code review process. In practice, you end up using the combined set of C++ sublanguages each contributor chooses to…
Re: Workarounds for C11 _Generic()
#39Earlier quoted context omitted.
Macros and #ifdef do not solve the problems that _Generic is used for. _Generic is for static polymorphism, not for target or build configuration.
Macros are perfectly capable of static polymorphism. That is one of their primary use cases. _Generic is simply an alternative mechanism for static polymorphism, with some extra capabilities and some limitations in comparison to your typical macro.
Re: Workarounds for C11 _Generic()
#40 #define length(x) _Generic(x, \
char * : strlen((char*)(x)), \
String * : ((String*)(x))->len \
)