www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Proposal: Object/?? Destruction

reply aberba <karabutaworld gmail.com> writes:
  Upon reading this, It triggered an idea.
 On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan Marler 
 wrote:
 https://wiki.dlang.org/DIP88

 I'd like to see DIP88 (Named Parameters) revived.  Was this 
 proposal rejected or is it just stale and needs a refresh?  
 Named parameters can be implemented in a library, however, in 
 my opinion they are useful enough to warrant a clean syntax 
 with language support.  I'd be willing to refresh the DIP so 
 long as I know the idea has not already been rejected.
DIP reminds me of object destruction. /* extracts success & message from returned type. Could be tuple or structure, etc. May even eliminate use of tuples for multiple return */ auto {success, message} = callVoldermortFunction(); This is concept is used in Kotlin. JavaScript es6 takes it even further (function parameters and arguments support object destruction)
Oct 04
next sibling parent Ilya Yaroshenko <ilyayaroshenko gmail.com> writes:
On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:
 auto {success, message} = callVoldermortFunction();
❤❤❤❤❤ I want this syntax, plz! This solves the issue how to return multiple ref values. --Ilya
Oct 04
prev sibling next sibling parent SrMordred <patric.dexheimer gmail.com> writes:
On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:
  Upon reading this, It triggered an idea.
 On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan 
 Marler wrote:
 [...]
DIP reminds me of object destruction. /* extracts success & message from returned type. Could be tuple or structure, etc. May even eliminate use of tuples for multiple return */ auto {success, message} = callVoldermortFunction(); This is concept is used in Kotlin. JavaScript es6 takes it even further (function parameters and arguments support object destruction)
+1
Oct 04
prev sibling next sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:
  Upon reading this, It triggered an idea.
 On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan 
 Marler wrote:
 https://wiki.dlang.org/DIP88

 I'd like to see DIP88 (Named Parameters) revived.  Was this 
 proposal rejected or is it just stale and needs a refresh?  
 Named parameters can be implemented in a library, however, in 
 my opinion they are useful enough to warrant a clean syntax 
 with language support.  I'd be willing to refresh the DIP so 
 long as I know the idea has not already been rejected.
DIP reminds me of object destruction. /* extracts success & message from returned type. Could be tuple or structure, etc. May even eliminate use of tuples for multiple return */ auto {success, message} = callVoldermortFunction(); This is concept is used in Kotlin. JavaScript es6 takes it even further (function parameters and arguments support object destruction)
People often call this "destructuring" or "unpacking" to avoid confusion with destructors.
Oct 04
next sibling parent bitwise <bitwise.pvt gmail.com> writes:
On Wednesday, 4 October 2017 at 12:06:43 UTC, John Colvin wrote:
 [...]

 People often call this "destructuring" or "unpacking" to avoid 
 confusion with destructors.
Or "Structured Bindings" ;) http://en.cppreference.com/w/cpp/language/structured_binding
Oct 04
prev sibling next sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 10/04/2017 05:06 AM, John Colvin wrote:

 People often call this "destructuring"
Thanks! Now it makes sense. :) Ali
Oct 04
prev sibling parent aberba <karabutaworld gmail.com> writes:
On Wednesday, 4 October 2017 at 12:06:43 UTC, John Colvin wrote:
 On Wednesday, 4 October 2017 at 10:03:56 UTC, aberba wrote:
  Upon reading this, It triggered an idea.
 People often call this "destructuring" or "unpacking" to avoid 
 confusion with destructors.
Thats the word I was looking for. Ha ha
Oct 04
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04.10.2017 12:03, aberba wrote:
   Upon reading this, It triggered an idea.
 On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan Marler wrote:
 https://wiki.dlang.org/DIP88

 I'd like to see DIP88 (Named Parameters) revived.  Was this proposal 
 rejected or is it just stale and needs a refresh? Named parameters 
 can be implemented in a library, however, in my opinion they are 
 useful enough to warrant a clean syntax with language support.  I'd 
 be willing to refresh the DIP so long as I know the idea has not 
 already been rejected.
DIP reminds me of object destruction. /* extracts success & message from returned type. Could be tuple or structure, etc. May even eliminate use of tuples for multiple return */ auto {success, message} = callVoldermortFunction();  This is concept is used in Kotlin. JavaScript es6 takes it even further (function parameters and arguments support object destruction)
Why curly braces? Multiple function arguments are a form of built-in tuple, so the syntax should be consistent: auto (success, message) = callVoldemortFunction(); 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.
Oct 04
next sibling parent reply Seb <seb wilzba.ch> writes:
On Thursday, 5 October 2017 at 06:42:14 UTC, Timon Gehr wrote:
 On 04.10.2017 12:03, aberba wrote:
   Upon reading this, It triggered an idea.
 On Saturday, 30 September 2017 at 16:10:44 UTC, Jonathan 
 Marler wrote:
 [...]
DIP reminds me of object destruction. /* extracts success & message from returned type. Could be tuple or structure, etc. May even eliminate use of tuples for multiple return */ auto {success, message} = callVoldermortFunction();  This is concept is used in Kotlin. JavaScript es6 takes it even further (function parameters and arguments support object destruction)
Why curly braces? Multiple function arguments are a form of built-in tuple, so the syntax should be consistent: auto (success, message) = callVoldemortFunction();
I think I can state the opinion of many D users here: I don't mind whether it will be curly braces or round parentheses - the important thing is that we will be able to use it in the foreseeable future :)
 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.
+1
Oct 05
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 05.10.2017 17:23, Seb wrote:
 auto {success, message} = callVoldermortFunction();

   This is concept is used in Kotlin. JavaScript es6 takes it even 
 further (function parameters and arguments support object destruction)
Why curly braces? Multiple function arguments are a form of built-in tuple, so the syntax should be consistent: auto (success, message) = callVoldemortFunction();
I think I can state the opinion of many D users here: I don't mind whether it will be curly braces or round parentheses - the important thing is that we will be able to use it in the foreseeable future :)
 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.
+1
I'll create a DIP as soon as I can.
Oct 05
prev sibling parent sarn <sarn theartofmachinery.com> writes:
On Thursday, 5 October 2017 at 15:23:26 UTC, Seb wrote:
 I think I can state the opinion of many D users here: I don't 
 mind whether it will be curly braces or round parentheses - the 
 important thing is that we will be able to use it in the 
 foreseeable future :)
All my +1s. Let's leave syntax details to people who know the D grammar inside out.
Oct 05
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
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. Why isn't (a) good enough? -Steve
Oct 05
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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?
 
 -Steve
typeof((a)) should be typeof(a). This is just a parenthesized expression, as in (a+b)*c. typeof((a,)) should be (typeof(a),). (I'm not super keen on conflating the type of a tuple with a tuple of types, but this has precedent in alias sequences, and I think it will be intuitive to most D users. FWIW, Haskell also does this.) My intention is to disentangle the concepts "function argument" and "multiple values" as much as possible. For example: --- (int,string,double) foo(int a,string b,double c){ return (a,b,c); } (int,string) bar(int a,string b,double c){ return (a,b); } void main(){ auto x = foo(1,"2",3.0); // ok, typeof(x) is (int,string double) // ^^^^^^^^^^^ // syntax of function argument is the same as the // syntax for a free-standing tuple: auto y = (1,"2",3.0); // all functions take a single argument, so you can construct // the tuple either at the call site, or before that: (int a,string b,double c) = foo(y); // ok auto (x,y,z) = foo(a,b,c); // ok // This allows natural composition of functions. // It is like DIP 35 except better: writeln([(1,"2",3.0), (4,"5",6.0)].map!foo.map!bar); } --- --- (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; } --- --- 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,) } ---
Oct 05
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
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
Oct 06
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06.10.2017 14:26, Steven Schveighoffer wrote:
 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? ...
This could be made to compile, but this is not really about tuples.
 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.
 ...
That's not necessarily bad. (When is the last time you have used a singleton tuple?)
 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,
It's the comma that indicates tupling, so there is not really ambiguity, the expression (a) just is not a tuple. To indicate a tuple you need to use the tupling operator ','. Trailing commas are allowed for all tuples, but for singleton tuples they are also necessary.
 but there would be no ambiguity if you used something other 
 than current punctuation to surround the tuple.
 
 Angle brackets come to mind <a>.
D avoids angle brackets.
 Also you could use a leading symbol to 
 change the meaning of the parentheses, like $(a).
 ...
This is very noisy, and once you go with non-standard tuple syntax, you can just as well use tuple(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). ...
AliasSeq auto-expands. If you call a function with a single element AliasSeq, it will expand to a single value and not be an AliasSeq anymore. Built-in tuples should not auto-expand, so a singleton tuple stays a singleton tuple (they will have an explicit .expand property).
 In your second example, where foo takes a 2-element tuple or 2 values, 
All functions take a single value. That value might be a tuple. (Of course, we will continue to say that a function can take multiple arguments, because it is convenient, but what this _means_ is that it takes a single tuple argument.)
 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? 
Yes. (Both options are "the tuple version".)
 This seems to contradict your example above.
 ...
No. All functions take one argument and produce one result. (The argument and the result may or may not be a tuple, but there is no essential difference between the two cases.) You can match a value against a pattern on the function call. The following are equivalent: (int,string) foo(){ // unpack at initialization of local variables of `foo` // pattern: (int a, string b) // value: (1,"2") (int a, string b) = (1,"2"); return (a,b); } (int,string) foo(){ auto match(int a, string b){ return (a,b); } // unpack at initialization of parameters of 'match' // pattern: (int a, string b) // value: (1,"2") return match(1,"2"); } Consider the following two different ways to achieve the same result: (int,string) foo(){ (int a, string b) = (1,"2"); return (a,b); } (int,string) bar(){ (int,string) x = (1,"2"); return x; } We can also rewrite bar in terms of a local match function: (int,string) bar(){ auto match((int,string) x){ return x; } return match(1,"2"); } Generally, if you have a function call like: foo(...) You can consider the part (...) in isolation as an expression. This will be your function argument: foo(); // function argument: () foo(1); // function argument: (1) foo(2,); // function argument: (2,) foo(1,2);// function argument: (1,2)
 ---
 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.
The proposal is to make all arguments "single type arguments". The "single type" might be a tuple. A tuple type is just a type, after all. For two current functions where only one matches but after the change both would match, the same one would still be selected, because it is more specialized. I.e., if for some reason you have: void foo(T)(T x){ // ... } void foo(T,S)(T a,S b){ // ... } void foo(T...)(T args){ // ... } Then the call foo(2) will still go to the first overload and the call foo(1,2) will still go to the second overload, while the call foo(1,2,3) will still go to the third overload. What relevant use case would break? (I can see the case where a cross-module overload becomes ambiguous, but that seems a little contrived.)
Oct 06
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 6 October 2017 at 19:31:11 UTC, Timon Gehr wrote:
 The proposal is to make all arguments "single type arguments". 
 The "single type" might be a tuple. A tuple type is just a 
 type, after all. For two current functions where only one 
 matches but after the change both would match, the same one 
 would still be selected, because it is more specialized.

 [snip]
 Then the call foo(2) will still go to the first overload and 
 the call foo(1,2) will still go to the second overload, while 
 the call foo(1,2,3) will still go to the third overload.
So under your thinking, the original example should have been something like: --- auto id(T)(T x){ return x; } void main(){ auto a = id(2); // ok, a is 2. auto b = id(1,2); // error, b is not single type argument auto c = id(1,); // ok, c is 1. auto d = id((1,2)); // ok, d is (1,2) auto e = id((1,)); // ok, e is (1,) } ---
Oct 06
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 06.10.2017 21:43, jmh530 wrote:
 On Friday, 6 October 2017 at 19:31:11 UTC, Timon Gehr wrote:
 The proposal is to make all arguments "single type arguments". The 
 "single type" might be a tuple. A tuple type is just a type, after 
 all. For two current functions where only one matches but after the 
 change both would match, the same one would still be selected, because 
 it is more specialized.

 [snip]
 Then the call foo(2) will still go to the first overload and the call 
 foo(1,2) will still go to the second overload, while the call 
 foo(1,2,3) will still go to the third overload.
So under your thinking, the original example should have been something like: --- auto id(T)(T x){ return x; } void main(){     auto a = id(2); // ok, a is 2.     auto b = id(1,2); // error, b is not single type argument     auto c = id(1,); // ok, c is 1.     auto d = id((1,2)); // ok, d is (1,2)     auto e = id((1,)); // ok, e is (1,) } ---
No, under my thinking the original example should have been what it was. Enclosing an expression in an additional set of parentheses does not change its semantics. This is true even if one set of parentheses is part of the function call.
Oct 06
parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 6 October 2017 at 19:51:39 UTC, Timon Gehr wrote:
 No, under my thinking the original example should have been 
 what it was.
 Enclosing an expression in an additional set of parentheses 
 does not change its semantics. This is true even if one set of 
 parentheses is part of the function call.
Hmm, I hadn't realized that you can have multiple sets of parentheses without error. I was assuming you would treat the second set as a tuple.
Oct 06
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/6/17 3:31 PM, Timon Gehr wrote:
 On 06.10.2017 14:26, Steven Schveighoffer wrote:
 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? ...
This could be made to compile, but this is not really about tuples.
 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.
 ...
That's not necessarily bad. (When is the last time you have used a singleton tuple?)
 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,
It's the comma that indicates tupling, so there is not really ambiguity, the expression (a) just is not a tuple. To indicate a tuple you need to use the tupling operator ','. Trailing commas are allowed for all tuples, but for singleton tuples they are also necessary.
 but there would be no ambiguity if you used something other than 
 current punctuation to surround the tuple.

 Angle brackets come to mind <a>.
D avoids angle brackets.
 Also you could use a leading symbol to change the meaning of the 
 parentheses, like $(a).
 ...
This is very noisy, and once you go with non-standard tuple syntax, you can just as well use tuple(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). ...
AliasSeq auto-expands. If you call a function with a single element AliasSeq, it will expand to a single value and not be an AliasSeq anymore. Built-in tuples should not auto-expand, so a singleton tuple stays a singleton tuple (they will have an explicit .expand property).
 In your second example, where foo takes a 2-element tuple or 2 values, 
All functions take a single value. That value might be a tuple. (Of course, we will continue to say that a function can take multiple arguments, because it is convenient, but what this _means_ is that it takes a single tuple argument.)
 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? 
Yes. (Both options are "the tuple version".)
 This seems to contradict your example above.
 ...
No. All functions take one argument and produce one result. (The argument and the result may or may not be a tuple, but there is no essential difference between the two cases.) You can match a value against a pattern on the function call.
It is weird to me that a function with 2 parameters is the same as a function that takes a 2-element tuple, but a function with one parameter is not the same as a function that takes a 1-element tuple. That is where I feel it's a contradiction.
 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.
The proposal is to make all arguments "single type arguments". The "single type" might be a tuple. A tuple type is just a type, after all. For two current functions where only one matches but after the change both would match, the same one would still be selected, because it is more specialized.
Right, but cases where T is expected to match to exactly one type will now match with multiple types. It messes up is(typeof(...)) checks. -Steve
Oct 06
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 5 October 2017 at 06:42:14 UTC, Timon Gehr wrote:
 Why curly braces? Multiple function arguments are a form of 
 built-in tuple, so the syntax should be consistent:

 auto (success, message) = callVoldemortFunction();

 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.
The curly bracket syntax looks straight out of DIP 32 https://wiki.dlang.org/DIP32 auto {x, y} = {1, "hi"};.
Oct 05
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 05.10.2017 17:48, jmh530 wrote:
 On Thursday, 5 October 2017 at 06:42:14 UTC, Timon Gehr wrote:
 Why curly braces? Multiple function arguments are a form of built-in 
 tuple, so the syntax should be consistent:

 auto (success, message) = callVoldemortFunction();

 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.
The curly bracket syntax looks straight out of DIP 32 https://wiki.dlang.org/DIP32 auto {x, y} = {1, "hi"};.
There are many good ideas in DIP32, including this one:
 Basic () syntax, perhaps the cleanest, but can't be used:
 
 ----
 import std.stdio, std.algorithm, std.container, std.array;
 
 auto encode(T)(Group!("a == b", T[]) sf) {
     auto heap = sf.map!((c, f) => (f, [(c, "")])).array.heapify!q{b < a};
 
     while (heap.length > 1) {
         auto (lof, loa) = heap.front;  heap.removeFront;
         auto (hif, hia) = heap.front;  heap.removeFront;
         foreach ((_, ref e); loa) e = '0' ~ e;
         foreach ((_, ref e); hia) e = '1' ~ e;
         heap.insert((lof + hif, loa ~ hia));
     }
     return heap.front[1].schwartzSort!((c, e) => (e.length, c));
 }
 
 void main() {
     auto s = "this is an example for huffman encoding"d;
     foreach ((c, e); s.dup.sort().release.group.encode)
         writefln("'%s'  %s", c, e);
 }
 ---
The reason why back then it seemed as if it "can't be used" is that it was taken by the comma operator. This is no longer the case.
Oct 05
parent jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 5 October 2017 at 19:55:15 UTC, Timon Gehr wrote:
 The reason why back then it seemed as if it "can't be used" is 
 that it was taken by the comma operator. This is no longer the 
 case.
Fair enough. I only didn't have an issue with it because I had recalled it when reading the previous DIP.
Oct 05