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

Reply via email to