www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Tuple mixins

reply Max Samukha <samukha voliacable.com.removethis> writes:
The mixin form compiles and works in some cases (in others it fails).
Is it legal at all? Is it mentioned anywhere in the specs? 

The following declares an int array and initializes it to the last
element encoded in the mixin string ([3]). Should the mixin fail with
an appropriate error or initialize the array to [1, 2, 3]?

void main()
{ 
  int[] arrr = [mixin("1, 2, 3")];
  writefln(arrr);
}
May 11 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Max Samukha wrote:
 The mixin form compiles and works in some cases (in others it fails).
 Is it legal at all? Is it mentioned anywhere in the specs? 
 
 The following declares an int array and initializes it to the last
 element encoded in the mixin string ([3]). Should the mixin fail with
 an appropriate error or initialize the array to [1, 2, 3]?
 
 void main()
 { 
   int[] arrr = [mixin("1, 2, 3")];
   writefln(arrr);
 }

The problem here is that mixins are not direct string mixins. That is, they don't simply spit their argument into the AST like a C preprocessor macro would. There are two kinds of string mixins: statement and expression. The one above is an expression mixin. Let's look at it a different way: int[] arr = [( mixin("1,2,3") )]; If you look at it like that, you see that "1,2,3" is not a tuple at all; it's a comma-delimited list of expressions which itself evaluates to the *last* expression. If you wanted to actually mix in a tuple, you'd have to be a bit more creative: int[] arr = [mixin("Tuple!(1,2,3)")]; // Note: not tested I ran across this when I was trying to generate functions with a particular name. Turns out this *doesn't* work:
 void mixin(identName)()
 {
     // Do stuff
 }

Basically, simple rule of thumb is: when mixing in an expression, mentally put a pair of parentheses around it; it helps you work out exactly what it's going to do. -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 11 2007
next sibling parent Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 11 May 2007 18:43:06 +1000, Daniel Keep
<daniel.keep.lists gmail.com> wrote:

Max Samukha wrote:
 The mixin form compiles and works in some cases (in others it fails).
 Is it legal at all? Is it mentioned anywhere in the specs? 
 
 The following declares an int array and initializes it to the last
 element encoded in the mixin string ([3]). Should the mixin fail with
 an appropriate error or initialize the array to [1, 2, 3]?
 
 void main()
 { 
   int[] arrr = [mixin("1, 2, 3")];
   writefln(arrr);
 }

The problem here is that mixins are not direct string mixins. That is, they don't simply spit their argument into the AST like a C preprocessor macro would. There are two kinds of string mixins: statement and expression. The one above is an expression mixin. Let's look at it a different way: int[] arr = [( mixin("1,2,3") )]; If you look at it like that, you see that "1,2,3" is not a tuple at all; it's a comma-delimited list of expressions which itself evaluates to the *last* expression.

Thanks, Daniel. I know about the expression and statement mixins. What I wanted to ask is why my example compiles? Is it a compiler bug or another type of mixin partially (or incorrectly) implemented? Note, that the mixin compiles in other similar contexts: void foo(int a/*, int b, int c */) { writefln(a); // outputs 3 } void main() { foo(mixin("1, 2, 3")); }
If you wanted to actually mix in a tuple, you'd have to be a bit more
creative:

int[] arr = [mixin("Tuple!(1,2,3)")]; // Note: not tested

Then I'd do it like this: int[] arr = mixin("[1,2,3]"); //ok, [1,2,3] is a complete expression
I ran across this when I was trying to generate functions with a
particular name.  Turns out this *doesn't* work:

 void mixin(identName)()
 {
     // Do stuff
 }

Basically, simple rule of thumb is: when mixing in an expression, mentally put a pair of parentheses around it; it helps you work out exactly what it's going to do. -- Daniel

May 11 2007
prev sibling next sibling parent Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 11 May 2007 18:43:06 +1000, Daniel Keep
<daniel.keep.lists gmail.com> wrote:

int[] arr = [mixin("Tuple!(1,2,3)")]; // Note: not tested

BTW, this one works. Thanks
May 11 2007
prev sibling parent reply Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 11 May 2007 18:43:06 +1000, Daniel Keep
<daniel.keep.lists gmail.com> wrote:

Max Samukha wrote:
 The mixin form compiles and works in some cases (in others it fails).
 Is it legal at all? Is it mentioned anywhere in the specs? 
 
 The following declares an int array and initializes it to the last
 element encoded in the mixin string ([3]). Should the mixin fail with
 an appropriate error or initialize the array to [1, 2, 3]?
 
 void main()
 { 
   int[] arrr = [mixin("1, 2, 3")];
   writefln(arrr);
 }

The problem here is that mixins are not direct string mixins. That is, they don't simply spit their argument into the AST like a C preprocessor macro would. There are two kinds of string mixins: statement and expression. The one above is an expression mixin. Let's look at it a different way: int[] arr = [( mixin("1,2,3") )]; If you look at it like that, you see that "1,2,3" is not a tuple at all; it's a comma-delimited list of expressions which itself evaluates to the *last* expression. If you wanted to actually mix in a tuple, you'd have to be a bit more creative: int[] arr = [mixin("Tuple!(1,2,3)")]; // Note: not tested I ran across this when I was trying to generate functions with a particular name. Turns out this *doesn't* work:
 void mixin(identName)()
 {
     // Do stuff
 }

Basically, simple rule of thumb is: when mixing in an expression, mentally put a pair of parentheses around it; it helps you work out exactly what it's going to do. -- Daniel

Using your rule of thumb I discovered that expressions separated by comma, in parentheses, can be used in contexts where tuples are allowed. Seems like D is going to have built-in expression tuple literals. Cool. Has it been discussed anywhere? void foo(int a /*, int b, int c*/) { } void main() { auto tuple = (1, 2, 3); auto arr = [tuple]; // arr = [(1, 2, 3)] compiles too foo(tuple); }
May 11 2007
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
Max Samukha wrote:
 [...]
 
 Using your rule of thumb I discovered that expressions separated by
 comma, in parentheses, can be used in contexts where tuples are
 allowed. Seems like D is going to have built-in expression tuple
 literals. Cool. Has it been discussed anywhere?
 
 void foo(int a /*, int b, int c*/)
 {
 }
 
 void main()
 {
  auto tuple = (1, 2, 3);
  auto arr = [tuple]; // arr = [(1, 2, 3)] compiles too
  foo(tuple);
 }

I think you're confused as to what's happening. From the D spec: """ Expressions Expression: AssignExpression AssignExpression , Expression The left operand of the , is evaluated, then the right operand is evaluated. The type of the expression is the type of the right operand, and the result is the result of the right operand. """ What's happening is that (1, 2, 3) evaluates to *3*. If you did this: (writefln("foo"), writefln("bar"), 42), it would print out "foo" and "bar" and evaluate to 42. They're not tuples, otherwise your foo(tuple) call would have failed, since you would have had three values for a function that only takes one. If you print out "arr", I think you'll find it's equal to [3] :P This is one thing I've never especially liked about C, C++ and now D. I personally thing that the comma should be used to construct tuples like it is in Python, which is a hell of a lot more useful. Plus, this behaviour is really friggin' weird :P -- Daniel -- int getRandomNumber() { return 4; // chosen by fair dice roll. // guaranteed to be random. } http://xkcd.com/ v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/
May 11 2007
next sibling parent Max Samukha <samukha voliacable.com.removethis> writes:
On Fri, 11 May 2007 21:52:17 +1000, Daniel Keep
<daniel.keep.lists gmail.com> wrote:

Max Samukha wrote:
 [...]
 
 Using your rule of thumb I discovered that expressions separated by
 comma, in parentheses, can be used in contexts where tuples are
 allowed. Seems like D is going to have built-in expression tuple
 literals. Cool. Has it been discussed anywhere?
 
 void foo(int a /*, int b, int c*/)
 {
 }
 
 void main()
 {
  auto tuple = (1, 2, 3);
  auto arr = [tuple]; // arr = [(1, 2, 3)] compiles too
  foo(tuple);
 }

I think you're confused as to what's happening. From the D spec: """ Expressions Expression: AssignExpression AssignExpression , Expression The left operand of the , is evaluated, then the right operand is evaluated. The type of the expression is the type of the right operand, and the result is the result of the right operand. """

separated expressions?
What's happening is that (1, 2, 3) evaluates to *3*.  If you did this:
(writefln("foo"), writefln("bar"), 42), it would print out "foo" and
"bar" and evaluate to 42.

They're not tuples, otherwise your foo(tuple) call would have failed,
since you would have had three values for a function that only takes
one.  If you print out "arr", I think you'll find it's equal to [3] :P

This is one thing I've never especially liked about C, C++ and now D.  I
personally thing that the comma should be used to construct tuples like
it is in Python, which is a hell of a lot more useful.  Plus, this
behaviour is really friggin' weird :P

Absolutely agree.
May 11 2007
prev sibling next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Daniel Keep wrote:
 
 
 This is one thing I've never especially liked about C, C++ and now D.  I
 personally thing that the comma should be used to construct tuples like
 it is in Python, which is a hell of a lot more useful.  Plus, this
 behaviour is really friggin' weird :P
 

Amen to that brutha. It's main use in C and C++ is hackish macro tricks. In C++ it also finds use as an overloadable operator you can use to confuse the heck out of people. Are there any good uses for it? Maybe the lists of initializers in for loops are using that rule? like -- for(x=3,y=10; x<y; x++) { ... }. Seems like you could make that part of the for loop grammar instead of a really useless works anywhere rule. Besides if it worked as a tuple maker, and multiple assigment worked then you could do for (x,y=3,10; x<y; x++) { . . . } Definitely seems like a waste. --bb
May 11 2007
next sibling parent Johan Granberg <lijat.meREM OVEgmail.com> writes:
Bill Baxter wrote:

 Daniel Keep wrote:
 
 
 This is one thing I've never especially liked about C, C++ and now D.  I
 personally thing that the comma should be used to construct tuples like
 it is in Python, which is a hell of a lot more useful.  Plus, this
 behaviour is really friggin' weird :P
 

Amen to that brutha. It's main use in C and C++ is hackish macro tricks. In C++ it also finds use as an overloadable operator you can use to confuse the heck out of people. Are there any good uses for it? Maybe the lists of initializers in for loops are using that rule? like -- for(x=3,y=10; x<y; x++) { ... }. Seems like you could make that part of the for loop grammar instead of a really useless works anywhere rule. Besides if it worked as a tuple maker, and multiple assigment worked then you could do for (x,y=3,10; x<y; x++) { . . . } Definitely seems like a waste. --bb

We can hope that this is something Walter considers for D2.0
May 11 2007
prev sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message 
news:f21rdg$2spg$1 digitalmars.com...
 Are there any good uses for it?  Maybe the lists of initializers in for 
 loops are using that rule?    like  -- for(x=3,y=10; x<y; x++) { ... }.
 Seems like you could make that part of the for loop grammar instead of a 
 really useless works anywhere rule.

That's how it works in MiniD ;) I really hate the comma operator. It's just a waste.
May 11 2007
prev sibling parent Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Daniel Keep wrote:

 This is one thing I've never especially liked about C, C++ and now D.  I
 personally thing that the comma should be used to construct tuples like
 it is in Python, which is a hell of a lot more useful.  Plus, this
 behaviour is really friggin' weird :P

votes++ At least some kind of built-in tuple literals are needed.
May 11 2007