www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - question on tuples and expressions

reply "leo" <leo clw-online.de> writes:
Hi,
while I was reading the language specification I stumbled across the 
following problem:

Tuple!(int, int) x = Tuple!(1, 2);  // doesn't compile
Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

How can I initialize a tuple by providing another tuple?

I know it's still possible to assign each element of the tuple separately, 
I'm just wondering what sense it makes
to define an expression (1, 2) to be 2 of type int rather than (1, 2) of 
type (int, int).
Is there any case in which this would provide an advantage?

Leo 
Jan 05 2009
next sibling parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 05 Jan 2009 14:33:51 +0300, leo <leo clw-online.de> wrote:

 Hi,
 while I was reading the language specification I stumbled across the  
 following problem:

 Tuple!(int, int) x = Tuple!(1, 2);  // doesn't compile
 Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

 How can I initialize a tuple by providing another tuple?

 I know it's still possible to assign each element of the tuple  
 separately, I'm just wondering what sense it makes
 to define an expression (1, 2) to be 2 of type int rather than (1, 2) of  
 type (int, int).
 Is there any case in which this would provide an advantage?

 Leo 
You have two mistakes, one for each lines of code :) But you were close to right solutions. 1) Tuple!(int, int) x = Tuple!(1, 2); // doesn't compile Of course it doesn't, don't confuse type definition with a constructor call. In this case, "Tuple!(int, int)" is a type, and so is "Tuple!(1, 2)" (although template parameters are invalid; types are expected, not expressions). We could rewrite this line as follows: A x = B; // where A and B are type aliases What you need here is a constructor call: A x = A(1, 2); or Tuple!(int,int) x = Tuple!(int,int)(1, 2); 2) Tuple!(int, int) y = (1, 2); // leads to y being (2, 2) Here is another quest - what does the following lines do? int x = 1, 2; int y = (1, 2); They are absolutely the same and both initialize variables to 2, that's the way comma expression works (it evaluates all the expression and returns result of last expression). Same here: "Tuple!(int, int) y = (1, 2);" == "Tuple!(int, int) y = 2;" If you want per-member struct initialization, you should use curly braces instead: Tuple!(int, int) y = {1, 2}; Example for better understanding: struct Foo { int i; float f; string s; } Foo foo = { 42, 3.1415f, "hello" };
Jan 05 2009
parent reply "leo" <leo clw-online.de> writes:
 Hi,
 while I was reading the language specification I stumbled across the 
 following problem:

 Tuple!(int, int) x = Tuple!(1, 2);  // doesn't compile
 Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

 How can I initialize a tuple by providing another tuple?

 I know it's still possible to assign each element of the tuple 
 separately, I'm just wondering what sense it makes
 to define an expression (1, 2) to be 2 of type int rather than (1, 2) of 
 type (int, int).
 Is there any case in which this would provide an advantage?

 Leo
You have two mistakes, one for each lines of code :) But you were close to right solutions. 1) Tuple!(int, int) x = Tuple!(1, 2); // doesn't compile Of course it doesn't, don't confuse type definition with a constructor call. In this case, "Tuple!(int, int)" is a type, and so is "Tuple!(1, 2)" (although template parameters are invalid; types are expected, not expressions). We could rewrite this line as follows:
But template parameters also allow for expressions, so that tuples can also be expression tuples.
 A x = B; // where A and B are type aliases

 What you need here is a constructor call:

 A x = A(1, 2);

 or

 Tuple!(int,int) x = Tuple!(int,int)(1, 2);
This wouldn't work since Tuple!(int, int) has no opCall
 2) Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

 Here is another quest - what does the following lines do?

 int x =  1, 2;
 int y = (1, 2);
The above doesn't compile, because it's actually a declaration of a variable "int x = 1;" and another syntactically wrong one "int 2;". The comma is associated with the DeclarationStatement, not the expression. In the second line the parentheses tell the compiler to treat "1, 2" as an expression.
 They are absolutely the same and both initialize variables to 2, that's 
 the way comma expression works (it evaluates all the expression and 
 returns result of last expression).

 Same here:

 "Tuple!(int, int) y = (1, 2);" == "Tuple!(int, int) y = 2;"

 If you want per-member struct initialization, you should use curly braces 
 instead:

 Tuple!(int, int) y = {1, 2};
Curly braces won't work either, because Tuple!(int, int) can not be initialized per-member. I tried also Tuple!(int, int) x; x = (1, 2); // here I get an error message "forward reference to type (int, int) x = {1, 2}; // this produces a lot of "found 'EOF' instead of statement" errors I compiled with dmd v1.038, v2.014 and v2.022 It's not like I would ever need to initialize a tuple like that, I'm just curious anyway, thanks for the answer Leo
Jan 05 2009
parent reply "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 05 Jan 2009 18:58:54 +0300, leo <leo clw-online.de> wrote:

 Hi,
 while I was reading the language specification I stumbled across the  
 following problem:

 Tuple!(int, int) x = Tuple!(1, 2);  // doesn't compile
 Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

 How can I initialize a tuple by providing another tuple?

 I know it's still possible to assign each element of the tuple  
 separately, I'm just wondering what sense it makes
 to define an expression (1, 2) to be 2 of type int rather than (1, 2)  
 of type (int, int).
 Is there any case in which this would provide an advantage?

 Leo
You have two mistakes, one for each lines of code :) But you were close to right solutions. 1) Tuple!(int, int) x = Tuple!(1, 2); // doesn't compile Of course it doesn't, don't confuse type definition with a constructor call. In this case, "Tuple!(int, int)" is a type, and so is "Tuple!(1, 2)" (although template parameters are invalid; types are expected, not expressions). We could rewrite this line as follows:
But template parameters also allow for expressions, so that tuples can also be expression tuples.
 A x = B; // where A and B are type aliases

 What you need here is a constructor call:

 A x = A(1, 2);

 or

 Tuple!(int,int) x = Tuple!(int,int)(1, 2);
This wouldn't work since Tuple!(int, int) has no opCall
 2) Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

 Here is another quest - what does the following lines do?

 int x =  1, 2;
 int y = (1, 2);
The above doesn't compile, because it's actually a declaration of a variable "int x = 1;" and another syntactically wrong one "int 2;". The comma is associated with the DeclarationStatement, not the expression. In the second line the parentheses tell the compiler to treat "1, 2" as an expression.
The first line, yes (I didn't say it should compile). The second line does, in fact, assigns 2 to y (instead of 1). This is the same as your example but with int instead of Tuple(int,int).
 They are absolutely the same and both initialize variables to 2, that's  
 the way comma expression works (it evaluates all the expression and  
 returns result of last expression).

 Same here:

 "Tuple!(int, int) y = (1, 2);" == "Tuple!(int, int) y = 2;"

 If you want per-member struct initialization, you should use curly  
 braces instead:

 Tuple!(int, int) y = {1, 2};
Curly braces won't work either, because Tuple!(int, int) can not be initialized per-member. I tried also Tuple!(int, int) x; x = (1, 2); // here I get an error message "forward reference to type (int, int) x = {1, 2}; // this produces a lot of "found 'EOF' instead of statement" errors I compiled with dmd v1.038, v2.014 and v2.022 It's not like I would ever need to initialize a tuple like that, I'm just curious anyway, thanks for the answer Leo
Both work for me (dmd 2.012): import std.typecons; void main() { Tuple!(int, int) x = Tuple!(int, int)(1, 2); Tuple!(int, int) y = {1, 2}; }
Jan 05 2009
parent reply "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Mon, Jan 5, 2009 at 2:39 PM, Denis Koroskin <2korden gmail.com> wrote:
 Both work for me (dmd 2.012):

 import std.typecons;

 void main()
 {
   Tuple!(int, int) x = Tuple!(int, int)(1, 2);
   Tuple!(int, int) y = {1, 2};
 }
Now you're comparing apples and oranges :) A typical: template Tuple(T...) { alias T Tuple; } template does not behave anything like the one defined in std.typecons.
Jan 05 2009
parent "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 05 Jan 2009 22:42:30 +0300, Jarrett Billingsley
<jarrett.billingsley gmail.com> wrote:

 On Mon, Jan 5, 2009 at 2:39 PM, Denis Koroskin <2korden gmail.com> wrote:
 Both work for me (dmd 2.012):

 import std.typecons;

 void main()
 {
   Tuple!(int, int) x = Tuple!(int, int)(1, 2);
   Tuple!(int, int) y = {1, 2};
 }
Now you're comparing apples and oranges :) A typical: template Tuple(T...) { alias T Tuple; } template does not behave anything like the one defined in std.typecons.
When one talks about Foo and Foo is not a standard library type OR (like in this case) is a custom user-defined type, he should show its implementation. Since none was mentioned, I assumed he was talking about std.typecons.Tuple.
Jan 05 2009
prev sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Mon, Jan 5, 2009 at 6:33 AM, leo <leo clw-online.de> wrote:
 Hi,
 while I was reading the language specification I stumbled across the
 following problem:

 Tuple!(int, int) x = Tuple!(1, 2);  // doesn't compile
 Tuple!(int, int) y = (1, 2);    // leads to y being (2, 2)

 How can I initialize a tuple by providing another tuple?

 I know it's still possible to assign each element of the tuple separately,
 I'm just wondering what sense it makes
 to define an expression (1, 2) to be 2 of type int rather than (1, 2) of
 type (int, int).
 Is there any case in which this would provide an advantage?
It seems that the compiler isn't quite smart enough to understand an (int, int) initializer for an (int, int) variable. You can, however, let the compiler figure out the type of the variable from the initializer: auto x = Tuple!(1, 2); pragma(msg, typeof(x).stringof); // prints (int, int) Furthermore, assigning a tuple in a normal assignment works: x = Tuple!(6, 7); // fine
Jan 05 2009