Most vexing parse and p0745r0

97 views
Skip to first unread message

inkwizyt...@gmail.com

unread,
Apr 9, 2018, 9:33:58 AM4/9/18
to ISO C++ Standard - Future Proposals

In p0745r0 is introduced new syntax:

X f(Concept{T}&& a){ /* ... */ }

But after looking on it I get feeling this could end up in new most vexing parse MK 2:

X f(Concept{}); //forward function declaration
X h
(int{}); //new variable

Is this valid concern? Is possible that someone write code that will have opposite meaning than intended? Can same concept and type name exist in same scope?

Probably one thing for sure we will loose is ability automatic visual distinction:
Foo a(X()); //function, even if I wanted variable
Foo b(Y(1)); //variable
Foo f(Z{}); //C++11: always variable, C++20: ??, you need to know what Z is


Nicol Bolas

unread,
Apr 9, 2018, 10:06:37 AM4/9/18
to ISO C++ Standard - Future Proposals


On Monday, April 9, 2018 at 9:33:58 AM UTC-4, Marcin Jaczewski wrote:

In p0745r0 is introduced new syntax:

X f(Concept{T}&& a){ /* ... */ }

But after looking on it I get feeling this could end up in new most vexing parse MK 2:

X f(Concept{}); //forward function declaration
X h
(int{}); //new variable

Is this valid concern?

Nope. In order for that to compile, the compiler must see the declaration of `Concept`. And therefore, the compiler can see that `Concept` is a concept, not a typename. And therefore, the compiler knows what that is.

Now, it may be that the user is confused, but never the compiler.
 
Is possible that someone write code that will have opposite meaning than intended? Can same concept and type name exist in same scope?

Concepts are variables, and you can't have a typename and variable with the same name in the same scope.

Probably one thing for sure we will loose is ability automatic visual distinction:
Foo a(X()); //function, even if I wanted variable
Foo b(Y(1)); //variable
Foo f(Z{}); //C++11: always variable, C++20: ??, you need to know what Z is


And how is that any different from:

Foo f(Z); //May declare a template or non-template function; you need to know what Z is.

If you want good terse syntax, you're going to have to give up some form of visual inspection. C++ is out of good syntax for this sort of stuff, so we have to make due with what we have.

Besides, I would say that from the surrounding context, you'll know which is which. If its in a function, odds are good `Z` is a typename. If its in class scope, `Z` *must* be a concept, since you can't use parenthesis on default member initializers. If its in global scope, `Z` is probably a concept, since you'd usually write it as `Foo f = Z{};`. Also, concept names are not likely to be confused with typenames.

inkwizyt...@gmail.com

unread,
Apr 9, 2018, 11:10:27 AM4/9/18
to ISO C++ Standard - Future Proposals


On Monday, April 9, 2018 at 4:06:37 PM UTC+2, Nicol Bolas wrote:


On Monday, April 9, 2018 at 9:33:58 AM UTC-4, Marcin Jaczewski wrote:

In p0745r0 is introduced new syntax:

X f(Concept{T}&& a){ /* ... */ }

But after looking on it I get feeling this could end up in new most vexing parse MK 2:

X f(Concept{}); //forward function declaration
X h
(int{}); //new variable

Is this valid concern?

Nope. In order for that to compile, the compiler must see the declaration of `Concept`. And therefore, the compiler can see that `Concept` is a concept, not a typename. And therefore, the compiler knows what that is.

Now, it may be that the user is confused, but never the compiler.
 

This is whole point. In most vexing parse compiler is not confused too but user is.
 
Is possible that someone write code that will have opposite meaning than intended? Can same concept and type name exist in same scope?

Concepts are variables, and you can't have a typename and variable with the same name in the same scope.

Probably one thing for sure we will loose is ability automatic visual distinction:
Foo a(X()); //function, even if I wanted variable
Foo b(Y(1)); //variable
Foo f(Z{}); //C++11: always variable, C++20: ??, you need to know what Z is


And how is that any different from:

Foo f(Z); //May declare a template or non-template function; you need to know what Z is.


How it could declare template in `C++17`? If `Z` is value then we have variable `f`, if it type this will always be normal function, you will need drop `template` before it, but then it will be different thing.
 
If you want good terse syntax, you're going to have to give up some form of visual inspection. C++ is out of good syntax for this sort of stuff, so we have to make due with what we have.

I fully understand this, my question is how big will be side effects (if any) of this new syntax. I can easy live with examples I provide but I do not know if there is any more serious case where syntax could clash and do different thing that programmer wanted and excepted.

One thing I find that is similar to this is unnamed value template parameter:

template<Concept{T}> class A{}; // A<int>, T == int
template<Concept{T} V> class B1{}; // B1<5>
template<Concept{T} /*V*/> class B2{}; //ups, now is type not value parameter

Of corse this is minor inconveniences.

 
Besides, I would say that from the surrounding context, you'll know which is which. If its in a function, odds are good `Z` is a typename. If its in class scope, `Z` *must* be a concept, since you can't use parenthesis on default member initializers. If its in global scope, `Z` is probably a concept, since you'd usually write it as `Foo f = Z{};`. Also, concept names are not likely to be confused with typenames.


 Yes, most of this examples is comparable to `X * a;`. If this all then there is no problem, again I'm simply interested if there was analyze of this "side effects".

Nicol Bolas

unread,
Apr 9, 2018, 11:29:32 AM4/9/18
to ISO C++ Standard - Future Proposals
On Monday, April 9, 2018 at 11:10:27 AM UTC-4, Marcin Jaczewski wrote:
On Monday, April 9, 2018 at 4:06:37 PM UTC+2, Nicol Bolas wrote:


On Monday, April 9, 2018 at 9:33:58 AM UTC-4, Marcin Jaczewski wrote:

In p0745r0 is introduced new syntax:

X f(Concept{T}&& a){ /* ... */ }

But after looking on it I get feeling this could end up in new most vexing parse MK 2:

X f(Concept{}); //forward function declaration
X h
(int{}); //new variable

Is this valid concern?

Nope. In order for that to compile, the compiler must see the declaration of `Concept`. And therefore, the compiler can see that `Concept` is a concept, not a typename. And therefore, the compiler knows what that is.

Now, it may be that the user is confused, but never the compiler.
 

This is whole point. In most vexing parse compiler is not confused too but user is.

In the most vexing parse, the compiler is not doing what the user expected. You wrote a typename followed by parenthesis, expecting this to mean "default construct a prvalue of this type". The compiler sees a typename followed by parenthesis and assumes this means "function type". The code doesn't do what the user thought it would.

That's not the case here. You wrote a concept name followed by curly braces, expecting this to mean "concept constrained parameter". The compiler agrees with you. So there is no confusion.

The most vexing parse is about the confusion between the writer and the compiler. That's not what's happening here. If there is confusion, it is only between the reader and the writer/compiler. The writer's intent and the compiler's actions are in alignment. The writer knew it was a concept name, and the compiler agreed.

Is possible that someone write code that will have opposite meaning than intended? Can same concept and type name exist in same scope?

Concepts are variables, and you can't have a typename and variable with the same name in the same scope.

Probably one thing for sure we will loose is ability automatic visual distinction:
Foo a(X()); //function, even if I wanted variable
Foo b(Y(1)); //variable
Foo f(Z{}); //C++11: always variable, C++20: ??, you need to know what Z is


And how is that any different from:

Foo f(Z); //May declare a template or non-template function; you need to know what Z is.


How it could declare template in `C++17`?

I didn't say anything about C++17. I was comparing Herb's terse syntax with the Concepts TS version of terse templates, which doesn't use the `{}` after the concept name. The point being that terse syntax will either not be terse or will involve some ambiguity on the reader's part.

inkwizyt...@gmail.com

unread,
Apr 9, 2018, 3:10:00 PM4/9/18
to ISO C++ Standard - Future Proposals


On Monday, April 9, 2018 at 5:29:32 PM UTC+2, Nicol Bolas wrote:
On Monday, April 9, 2018 at 11:10:27 AM UTC-4, Marcin Jaczewski wrote:
On Monday, April 9, 2018 at 4:06:37 PM UTC+2, Nicol Bolas wrote:


On Monday, April 9, 2018 at 9:33:58 AM UTC-4, Marcin Jaczewski wrote:

In p0745r0 is introduced new syntax:

X f(Concept{T}&& a){ /* ... */ }

But after looking on it I get feeling this could end up in new most vexing parse MK 2:

X f(Concept{}); //forward function declaration
X h
(int{}); //new variable

Is this valid concern?

Nope. In order for that to compile, the compiler must see the declaration of `Concept`. And therefore, the compiler can see that `Concept` is a concept, not a typename. And therefore, the compiler knows what that is.

Now, it may be that the user is confused, but never the compiler.
 

This is whole point. In most vexing parse compiler is not confused too but user is.

In the most vexing parse, the compiler is not doing what the user expected. You wrote a typename followed by parenthesis, expecting this to mean "default construct a prvalue of this type". The compiler sees a typename followed by parenthesis and assumes this means "function type". The code doesn't do what the user thought it would.

That's not the case here. You wrote a concept name followed by curly braces, expecting this to mean "concept constrained parameter". The compiler agrees with you. So there is no confusion.

The most vexing parse is about the confusion between the writer and the compiler. That's not what's happening here. If there is confusion, it is only between the reader and the writer/compiler. The writer's intent and the compiler's actions are in alignment. The writer knew it was a concept name, and the compiler agreed.


I'm not arguing about this exactly situation with examples, as I said: "Yes, most of this examples is comparable to `X * a;`. If this all then there is no problem".
I'm not language layer to rule out that this is more different cases, this way I ask this there.

Right now you say that:

ConceptName + `{` -> type that can be template parameter, can only be used in declaration/definitions
TypeName + `{` -> new rvalue, can only be used in expressions

And this is enough to eliminate ANY possible overlap in syntax structure?

Nicol Bolas

unread,
Apr 9, 2018, 6:30:54 PM4/9/18
to ISO C++ Standard - Future Proposals

... yes.

The Most Vexing Parse happened because of the ambiguous nature of `TypeName + (`. That can sometimes mean initialize a prvalue and sometimes mean a function type. If both are viable within the context, the grammar will have to favor one over the other. And they picked "function type".

By contrast, right now `ConceptName + {` means nothing, since concepts are variables and `variable + {` doesn't mean anything. So it can be safely given whatever meaning we want. `TypeName + {` means to initialize a prvalue, and that need not change.

From a grammar standpoint, `identifier + {` will have to be able to lead to two different outcomes, but things like that already happen in C++. You can't really parse C++ as it is now without knowing what those identifiers mean based on previous declarations/definitions. This would simply be one more instance of that.

From a parsing perspective and writer/compiler agreement perspective, `ConceptName + {` is safe and unambiguous. It's context sensitive, but not ambiguous.

Richard Smith

unread,
Apr 9, 2018, 7:09:12 PM4/9/18
to std-pr...@isocpp.org
On 9 April 2018 at 07:06, Nicol Bolas <jmck...@gmail.com> wrote:
On Monday, April 9, 2018 at 9:33:58 AM UTC-4, Marcin Jaczewski wrote:

In p0745r0 is introduced new syntax:

X f(Concept{T}&& a){ /* ... */ }

But after looking on it I get feeling this could end up in new most vexing parse MK 2:

X f(Concept{}); //forward function declaration
X h
(int{}); //new variable

Is this valid concern?

Nope. In order for that to compile, the compiler must see the declaration of `Concept`. And therefore, the compiler can see that `Concept` is a concept, not a typename. And therefore, the compiler knows what that is.

Now, it may be that the user is confused, but never the compiler.
 
Is possible that someone write code that will have opposite meaning than intended? Can same concept and type name exist in same scope?

Concepts are variables, and you can't have a typename and variable with the same name in the same scope.

Probably one thing for sure we will loose is ability automatic visual distinction:
Foo a(X()); //function, even if I wanted variable
Foo b(Y(1)); //variable
Foo f(Z{}); //C++11: always variable, C++20: ??, you need to know what Z is


And how is that any different from:

Foo f(Z); //May declare a template or non-template function; you need to know what Z is.

If you want good terse syntax, you're going to have to give up some form of visual inspection.

I don't entirely agree: I would say that if you have to give up some form of visual inspection, you don't have a good terse syntax. Perhaps this means that we're forced to choose between a less-good terse syntax and no terse syntax at all, but that's an engineering tradeoff that we can and should make, and we should keep in mind that having only one option doesn't necessarily make that option good. (But conversely, "not good" doesn't mean "not an improvement"...)
 
C++ is out of good syntax for this sort of stuff, so we have to make due with what we have. 
Besides, I would say that from the surrounding context, you'll know which is which. If its in a function, odds are good `Z` is a typename. If its in class scope, `Z` *must* be a concept, since you can't use parenthesis on default member initializers. If its in global scope, `Z` is probably a concept, since you'd usually write it as `Foo f = Z{};`. Also, concept names are not likely to be confused with typenames.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/b1082776-de1a-4f25-bcc2-739dcc6897ab%40isocpp.org.

Reply all
Reply to author
Forward
0 new messages