Date: Fri, 26 Mar 2021 10:32:33 -0400
> On Mar 25, 2021, at 10:07 AM, Corentin via SG7 <sg7_at_[hidden]> wrote:
>
> Hello,
>
> P2342R0 - For a Few Punctuators More is a new paper of mine which argues that
> $, @ and ` could be used in the C++ grammar with minimal impact on the ecosystem, should reflection (or other feature) desire to use them.
>
> I unfortunately missed the March deadline so, until April, the paper can be found at https://isocpp.org/files/papers/P2342R0.pdf <https://isocpp.org/files/papers/P2342R0.pdf>
>
> I don't think it's worth presenting - the paper itself does not propose anything.
> I would simply ask that we do not dismiss $ or other syntaxes element simply for fear of affecting the ecosystem negatively!
This is a very thorough, useful paper. But more importantly, it has a great title :).
Your paper is of general use well beyond this particular use of $, and to alternative syntax proposals others may yet present, which I would be very interested to hear — IMO it is healthy to keep things stochastic at this point in case a more optimal solution can crystallize.
Given your findings I figure I would address how my thinking evolved on $, and why I soured on it just a bit, at least enough to make me think [::] is at least as good a solution at this point.
First, [::] will be used alongside |##| very frequently. Basically my understanding is that, for a reflection `x` of a named declaration:
```
|#meta::name_of(x)#| //splices the unqualified name of x into the program
[:x:] // splices the fully-qualified name of x (in a sense)
```
Indeed in P2237 [:x:] was ||, which suggested this similarity to |##|.
So, any change in syntax for one, probably should address the other. That is, if [::] becomes $, we need a similar change for |##|, otherwise there is not much point, aesthetically.
Thinking about this, I figured, why not just have $ handle both: for a meta::info operand, it returns [::], for a string opearand it returns |##|:
```
$meta::name_of(x) //splices the unqualified name of x into the program
$x // splices the fully-qualified name of x, in a sense
```
Note too the first way could be written `$(meta::name_of(x))` for clarity, but...probably should not need to be: if we adopt a unary operator, it seems to me it should probably follow the same grouping assumptions as operator*: the same way `*foo(a)` dereferences the result of `foo(a)`, `$meta::name_of(a)` should splice the result of `meta::name_of(a)`.
Note this is a change from the original conception that parens following $ could imply the grouping, e.g. $(detail::refl)::NonReflInner: I now think that would be a mistake, as it would break the analogy to operator*.
If we follow this operator* analogy, this means we also have to deal with the same difficulties we encounter when dereferencing function/method pointers, which Andrew discussed in his original response to my rough $ proposal (though again at the time the analogy between $ and * was not there, so the discussion was a tad different, but mostly on point).
I did not give such concerns much credence at the time: how often do you write dereferences of function/method pointers, vs. the usual dereferencing of non-function pointers? The extra parens needed to dereference the former seems appropriate to its relative rarity in code, in operator*’s case.
However, I think we would be writing them a lot with $, since we will often want to splice a name of a function into the program to declare that function, and in any such case we will need to write ($name)() in the very declaration of $name.
Let’s get to some actual code. Here are a few different conceivable ways of writing Andrew’s "property" example from Section 7 of P2237:
```
// Andrew’s original
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T |# %{member_name} #|;
public:
T const& |# %{getter_name} #|() const {
return |# %{member_name} #|;
}
void |# %{setter_name} #|(T const& x) {
|# %{member_name} #| = x;
}
}>;
}
// Andrew’s original, but let’s take out the %{}, in case
// we can ultimately figure out a good way to do without it
// (which would be great, per the previous discussion with
// Daveed).
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T |# member_name #|;
public:
T const& |# getter_name #|() const {
return |# member_name #|;
}
void |# setter_name #|(T const& x) {
|# member_name #| = x;
}
}>;
}
// No %{}, and |##| replaced by $ using operator*
// grouping assumptions:
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T $member_name;
public:
T const& ($member_name)() const {
return $member_name;
}
void ($setter_name)(T const& x) {
$member_name = x;
}
}>;
}
// $, with %{}:
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T $%{member_name};
public:
T const& ($%{member_name})() const {
return $%{member_name};
}
void ($%{setter_name})(T const& x) {
$%{member_name} = x;
}
}>;
}
```
I suppose looking at it now, ($name)() is not half bad (at least before %{} gets involved). So it might still be worth considering, but I can definitely see |##| and [::] as being better, and since they are the default now, they win. (It certainly seems more important is to get rid of %{}, if at all possible.)
I won’t be writing a formal paper proposing any of the above, but in case anyone else is writing something up, hopefully this discussion helps factor in all the considerations.
More importantly thanks Corentin for your very generally useful paper, which provides a basis on which these discussions can happen.
Dave
>
> Hello,
>
> P2342R0 - For a Few Punctuators More is a new paper of mine which argues that
> $, @ and ` could be used in the C++ grammar with minimal impact on the ecosystem, should reflection (or other feature) desire to use them.
>
> I unfortunately missed the March deadline so, until April, the paper can be found at https://isocpp.org/files/papers/P2342R0.pdf <https://isocpp.org/files/papers/P2342R0.pdf>
>
> I don't think it's worth presenting - the paper itself does not propose anything.
> I would simply ask that we do not dismiss $ or other syntaxes element simply for fear of affecting the ecosystem negatively!
This is a very thorough, useful paper. But more importantly, it has a great title :).
Your paper is of general use well beyond this particular use of $, and to alternative syntax proposals others may yet present, which I would be very interested to hear — IMO it is healthy to keep things stochastic at this point in case a more optimal solution can crystallize.
Given your findings I figure I would address how my thinking evolved on $, and why I soured on it just a bit, at least enough to make me think [::] is at least as good a solution at this point.
First, [::] will be used alongside |##| very frequently. Basically my understanding is that, for a reflection `x` of a named declaration:
```
|#meta::name_of(x)#| //splices the unqualified name of x into the program
[:x:] // splices the fully-qualified name of x (in a sense)
```
Indeed in P2237 [:x:] was ||, which suggested this similarity to |##|.
So, any change in syntax for one, probably should address the other. That is, if [::] becomes $, we need a similar change for |##|, otherwise there is not much point, aesthetically.
Thinking about this, I figured, why not just have $ handle both: for a meta::info operand, it returns [::], for a string opearand it returns |##|:
```
$meta::name_of(x) //splices the unqualified name of x into the program
$x // splices the fully-qualified name of x, in a sense
```
Note too the first way could be written `$(meta::name_of(x))` for clarity, but...probably should not need to be: if we adopt a unary operator, it seems to me it should probably follow the same grouping assumptions as operator*: the same way `*foo(a)` dereferences the result of `foo(a)`, `$meta::name_of(a)` should splice the result of `meta::name_of(a)`.
Note this is a change from the original conception that parens following $ could imply the grouping, e.g. $(detail::refl)::NonReflInner: I now think that would be a mistake, as it would break the analogy to operator*.
If we follow this operator* analogy, this means we also have to deal with the same difficulties we encounter when dereferencing function/method pointers, which Andrew discussed in his original response to my rough $ proposal (though again at the time the analogy between $ and * was not there, so the discussion was a tad different, but mostly on point).
I did not give such concerns much credence at the time: how often do you write dereferences of function/method pointers, vs. the usual dereferencing of non-function pointers? The extra parens needed to dereference the former seems appropriate to its relative rarity in code, in operator*’s case.
However, I think we would be writing them a lot with $, since we will often want to splice a name of a function into the program to declare that function, and in any such case we will need to write ($name)() in the very declaration of $name.
Let’s get to some actual code. Here are a few different conceivable ways of writing Andrew’s "property" example from Section 7 of P2237:
```
// Andrew’s original
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T |# %{member_name} #|;
public:
T const& |# %{getter_name} #|() const {
return |# %{member_name} #|;
}
void |# %{setter_name} #|(T const& x) {
|# %{member_name} #| = x;
}
}>;
}
// Andrew’s original, but let’s take out the %{}, in case
// we can ultimately figure out a good way to do without it
// (which would be great, per the previous discussion with
// Daveed).
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T |# member_name #|;
public:
T const& |# getter_name #|() const {
return |# member_name #|;
}
void |# setter_name #|(T const& x) {
|# member_name #| = x;
}
}>;
}
// No %{}, and |##| replaced by $ using operator*
// grouping assumptions:
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T $member_name;
public:
T const& ($member_name)() const {
return $member_name;
}
void ($setter_name)(T const& x) {
$member_name = x;
}
}>;
}
// $, with %{}:
template<typename T>
consteval meta::info property(string_view id) {
string member_name = “m_” + id;
string getter_name = “get_” + id;
string setter_name = “set_” + id;
return <class {
private:
T $%{member_name};
public:
T const& ($%{member_name})() const {
return $%{member_name};
}
void ($%{setter_name})(T const& x) {
$%{member_name} = x;
}
}>;
}
```
I suppose looking at it now, ($name)() is not half bad (at least before %{} gets involved). So it might still be worth considering, but I can definitely see |##| and [::] as being better, and since they are the default now, they win. (It certainly seems more important is to get rid of %{}, if at all possible.)
I won’t be writing a formal paper proposing any of the above, but in case anyone else is writing something up, hopefully this discussion helps factor in all the considerations.
More importantly thanks Corentin for your very generally useful paper, which provides a basis on which these discussions can happen.
Dave
Received on 2021-03-26 09:32:38