On 10/5/17 3:42 PM, Timon Gehr wrote:
On 05.10.2017 17:40, Steven Schveighoffer wrote:
On 10/5/17 2:42 AM, Timon Gehr wrote:
The only unresolved question is (as using the result of the comma
operator has been deprecated already): How to write a unary tuple. My
favourite is what python does: "(3,)". This is however already
accepted as a function argument list. I think it is worth breaking
though. Maybe we should deprecate it.
I know you have an answer for this, but pardon my ignorance.
I indeed have strong opinions on how to do this correctly, as I have
given some thought to it when designing the (still quite basic) type
system of PSI: https://github.com/eth-srl/psi
The idea is to follow type theory/mathematics where the type of
functions is a binary type constructor taking domain and codomain to the
type of functions mapping values from the domain to values from the
codomain. Multiple function arguments are just the function applied to a
tuple of values.
Why isn't (a) good enough?
typeof((a)) should be typeof(a). This is just a parenthesized
expression, as in (a+b)*c.
Right, I agree.
typeof((a,)) should be (typeof(a),).
I guess my question is more in the context of the problem at hand:
int foo();
auto (a) = foo();
why can't this work?
But then of course, it shouldn't work, because int is not a tuple. So I
suppose I have answered my own question -- we need a way to specify a
tuple of one for prototype foo!
Indeed, my experience with tuples and their usage is quite limited.
Even though the syntax is straightforward and unambiguous, it looks
incorrect, like you forgot something.
I'm not an expert in language design, but would it be worth exploring
other punctuation that isn't used in the language currently to allow
better syntax? It seems like the trailing comma is to get around
ambiguity, but there would be no ambiguity if you used something other
than current punctuation to surround the tuple.
Angle brackets come to mind <a>. Also you could use a leading symbol to
change the meaning of the parentheses, like $(a).
---
(int,) foo(int a){ return (a,); } // turn value into singleton tuple
int bar(int a,){ return a[0]; } // turn singleton tuple into value
void main(){
foo(2,); // error: cannot convert (int,) to int
bar(2); // error: cannot convert int to (int,)
auto (x,) = foo(2); // ok, x has type int
auto y = bar(2,); // ok y has type int
auto z = foo(2); // ok, z has type (int,)
}
---
---
// The following two function signatures are equivalent (identical name
mangling):
(int,string) foo(int a,string b){
return (a,b);
}
(int,string) foo((int,string) x){
return x;
}
---
So I will ask, what is the usage of foo here?
In the first example (foo and bar), you can't call a function that takes
a tuple with a single value, and you can't call a function that takes a
value with a single tuple (BTW, this is not how AliasSeq works, you can
call functions that take a single arg with single element tuples).
In your second example, where foo takes a 2-element tuple or 2 values,
you say the name mangling is equivalent. Does that mean if I only define
the tuple version, I can call it with foo(1, "hello") and vice versa?
This seems to contradict your example above.
---
auto id(T)(T x){ return x; }
void main(){
auto a = id(2); // ok, a is 2.
auto b = id(1,2); // ok, b is (1,2)
auto c = id(1,); // ok, c is (1,)
}
---
This would mess up a TON of code. I can say for certain, a single type
argument can never be made to accept a tuple.
-Steve