Date: Tue, 10 Mar 2020 17:14:59 +0100
Florian,
on Tue, 10 Mar 2020 16:32:40 +0100 you (Florian Weimer
<fw_at_[hidden]>) wrote:
> However, I think _Generic is largely a dead-end for things like math
> functions where even moderate nesting of expressions can be
> expected.
probably, as far as the core proposal goes, this uses mostly lambdas
for all the generic interfaces in math.h, for example.
> The problem is the separation into translation phases. A macro
> wrapping _Generic first needs to expanded, including all its
> alternatives, recursively. Only in later translation phases, the
> expression is again reduced to something manageable. In theory,
> merging translation phases could avoid this problem, but that looks
> like a kludge to me.
> For example, I don't think a fully usable implementation of <tgmath.h>
> using _Generic is possible. Joseph Myers probably has more insights
> about this topic. Here is what he wrote about support for an
> alternative implementation in GCC: ...
all yes
> C++ function overloading does not have this problem, even when
> implemented inefficiently: types for the most nested expression are
> determined first and then fixed, so the combinatorial explosion
> inherent to _Generic-based macros does not happen.
also yes
but ... that's not the thing, I have kept generic selection for
several reasons:
The first thing I try to achieve is portability. In C have don't have
the habit to tell people to throw away (or have major maintance) of
their code every other year. Removing such a thing from C is out of
the question, I think.
The second is, that generic selection is a very nice tool to implement
traits and similar things. Just as an example from the reference
implementation that I am trying to build currently and that
simultaneously generates generic selections for C and overloaded
functions for C++:
#define tohighest(X) _Generic((X), \
signed char: (signed char)(((unsigned char)-1)/2),\
signed short: (signed short)(((unsigned short)-1)/2),\
signed int: (signed int)(((unsigned int)-1)/2),\
signed long: (signed long)(((unsigned long)-1)/2),\
signed long long: (signed long long)(((unsigned long long)-1)/2),\
char: (char)(((unsigned char)-1)/(((char)-1 > 0) ? 1 : 2)),\
float: HUGE_VALF,\
double: HUGE_VAL,\
long double: HUGE_VALL,\
default: (generic_type(X))(((generic_type(X))-1)/(((generic_type(X))-1) < 0 ? 2 : 1)))
(the real code I have for this is even shorter, but that's another story)
Basically what the user has to write here is one line per type, which
is very concise and fits on one screen with a "tabular" layout (type
left, expression right). For C++ the generated code is 9 overloaded
functions and a template for the default case. This boiler plate
introduces a lot of possibilities for mistakes.
The third is, that I don't want to add function overloading to C,
because that would imply name mangling. This core proposal is meant to
be doable without any ABI changes and wihout changes to other
components of a tool chain than the compiler-proper plus library. (And
even there, a lot can be done by preloading of some includes and
source rewriting.)
The fourth is, that the `default` case needs a template, which we
obviously don't have in C and which we will probably never have, for
the same reasons.
If you look closely, I am asking already a lot from C, and very few
concessions from C++. Everybody would have to move a little bit to
accomodate the other.
Thanks
Jens
on Tue, 10 Mar 2020 16:32:40 +0100 you (Florian Weimer
<fw_at_[hidden]>) wrote:
> However, I think _Generic is largely a dead-end for things like math
> functions where even moderate nesting of expressions can be
> expected.
probably, as far as the core proposal goes, this uses mostly lambdas
for all the generic interfaces in math.h, for example.
> The problem is the separation into translation phases. A macro
> wrapping _Generic first needs to expanded, including all its
> alternatives, recursively. Only in later translation phases, the
> expression is again reduced to something manageable. In theory,
> merging translation phases could avoid this problem, but that looks
> like a kludge to me.
> For example, I don't think a fully usable implementation of <tgmath.h>
> using _Generic is possible. Joseph Myers probably has more insights
> about this topic. Here is what he wrote about support for an
> alternative implementation in GCC: ...
all yes
> C++ function overloading does not have this problem, even when
> implemented inefficiently: types for the most nested expression are
> determined first and then fixed, so the combinatorial explosion
> inherent to _Generic-based macros does not happen.
also yes
but ... that's not the thing, I have kept generic selection for
several reasons:
The first thing I try to achieve is portability. In C have don't have
the habit to tell people to throw away (or have major maintance) of
their code every other year. Removing such a thing from C is out of
the question, I think.
The second is, that generic selection is a very nice tool to implement
traits and similar things. Just as an example from the reference
implementation that I am trying to build currently and that
simultaneously generates generic selections for C and overloaded
functions for C++:
#define tohighest(X) _Generic((X), \
signed char: (signed char)(((unsigned char)-1)/2),\
signed short: (signed short)(((unsigned short)-1)/2),\
signed int: (signed int)(((unsigned int)-1)/2),\
signed long: (signed long)(((unsigned long)-1)/2),\
signed long long: (signed long long)(((unsigned long long)-1)/2),\
char: (char)(((unsigned char)-1)/(((char)-1 > 0) ? 1 : 2)),\
float: HUGE_VALF,\
double: HUGE_VAL,\
long double: HUGE_VALL,\
default: (generic_type(X))(((generic_type(X))-1)/(((generic_type(X))-1) < 0 ? 2 : 1)))
(the real code I have for this is even shorter, but that's another story)
Basically what the user has to write here is one line per type, which
is very concise and fits on one screen with a "tabular" layout (type
left, expression right). For C++ the generated code is 9 overloaded
functions and a template for the default case. This boiler plate
introduces a lot of possibilities for mistakes.
The third is, that I don't want to add function overloading to C,
because that would imply name mangling. This core proposal is meant to
be doable without any ABI changes and wihout changes to other
components of a tool chain than the compiler-proper plus library. (And
even there, a lot can be done by preloading of some includes and
source rewriting.)
The fourth is, that the `default` case needs a template, which we
obviously don't have in C and which we will probably never have, for
the same reasons.
If you look closely, I am asking already a lot from C, and very few
concessions from C++. Everybody would have to move a little bit to
accomodate the other.
Thanks
Jens
-- :: INRIA Nancy Grand Est ::: Camus ::::::: ICube/ICPS ::: :: ::::::::::::::: office Strasbourg : +33 368854536 :: :: :::::::::::::::::::::: gsm France : +33 651400183 :: :: ::::::::::::::: gsm international : +49 15737185122 :: :: http://icube-icps.unistra.fr/index.php/Jens_Gustedt ::
Received on 2020-03-10 11:17:52