www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - mixin troubles

reply Derek Parnell <derek nomail.afraid.org> writes:
Ok, I'm the first to admit that I don't understand the syntax of mixins. It
just seems *SO* unintuitive that it never sticks in my mind, and when I
look up the documentation I find that it is misleading and/or wrong.

Anyhow, what am I doing wrong here ...

 template Foo(alias b)
 {
    typeof(b) Foo() { return b; }
 }

 void main()
 {
    int a = 3;
    double b = 3.14;
    mixin Foo!(a) y;
    mixin Foo!(b) z;
    assert(y() == 3);
    assert(z() == 3.14);
 }


I was expecting that code to be equivalent to ...

 void main()
 {
    int a = 3;
    double b = 3.14;
    typeof(a) y() { return a; }
    typeof(b) z() { return b; }
    assert(y() == 3);
    assert(z() == 3.14);
 }

BTW, the docs say that the instantiation syntax for mixins is 


   mixin Foo!() a y;

that is that the template arguments are placed outside and following the
parenthesis, but that has just got to be wrong.

I quote ...

"
TemplateMixin:
	mixin TemplateIdentifier ;
	mixin TemplateIdentifier MixinIdentifier ;
	mixin TemplateIdentifier !() TemplateArgumentList  ;
	mixin TemplateIdentifier !() TemplateArgumentList  MixinIdentifier ;

MixinIdentifier:
	Identifier
"

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
3/10/2006 2:42:56 PM
Oct 02 2006
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:327lkdzeqky1$.11w3vhc3ana9f.dlg 40tude.net...

 Anyhow, what am I doing wrong here ...

 template Foo(alias b)
 {
    typeof(b) Foo() { return b; }
 }

 void main()
 {
    int a = 3;
    double b = 3.14;
    mixin Foo!(a) y;
    mixin Foo!(b) z;
    assert(y() == 3);
    assert(z() == 3.14);
 }

Mixins bug me too. Here's the "correct" version of your code: template Foo(alias b) { typeof(b) Foo() { return b; } } void main() { int a = 3; double b = 3.14; mixin .Foo!(a) y; mixin .Foo!(b) z; assert(y.Foo() == 3); assert(z.Foo() == 3.14); } Notice the global scope operators on the mixin instantiations, and the explicit access of y.Foo/z.Foo. The reason this happens is that the first mixin Foo!(a) y; mixes in the symbol Foo from inside the template. Then the second mixin attempts to use the local Foo, which is now a mixed-in function, as a template, which fails. So you have to use the global scope operator to access the actual template declaration. (Actually the first one is optional.) Then, you can't call y(), because although the function Foo is the same name as the mixin Foo, y is of type mixin Foo!(a), and the compiler doesn't interpret y() as a call to Foo.
 I was expecting that code to be equivalent to ...

 void main()
 {
    int a = 3;
    double b = 3.14;
    typeof(a) y() { return a; }
    typeof(b) z() { return b; }
    assert(y() == 3);
    assert(z() == 3.14);
 }

It would be great to be able to generate code like that.
 BTW, the docs say that the instantiation syntax for mixins is


   mixin Foo!() a y;

 that is that the template arguments are placed outside and following the
 parenthesis, but that has just got to be wrong.

 I quote ...

 "
 TemplateMixin:
 mixin TemplateIdentifier ;
 mixin TemplateIdentifier MixinIdentifier ;
 mixin TemplateIdentifier !() TemplateArgumentList  ;
 mixin TemplateIdentifier !() TemplateArgumentList  MixinIdentifier ;

 MixinIdentifier:
 Identifier
 "

I've noticed this in a lot of places in the docs; it showed up when Walter converted them all over to DDoc format. A lot of the instances have been fixed. I think he might just have his DDoc macros wrong.
Oct 03 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Wed, 4 Oct 2006 00:03:17 -0400, Jarrett Billingsley wrote:

 "Derek Parnell" <derek nomail.afraid.org> wrote in message 
 news:327lkdzeqky1$.11w3vhc3ana9f.dlg 40tude.net...
 
 Anyhow, what am I doing wrong here ...

 template Foo(alias b)
 {
    typeof(b) Foo() { return b; }
 }

 void main()
 {
    int a = 3;
    double b = 3.14;
    mixin Foo!(a) y;
    mixin Foo!(b) z;
    assert(y() == 3);
    assert(z() == 3.14);
 }

Mixins bug me too. Here's the "correct" version of your code:

Thanks for patience.
  template Foo(alias b)
  {
     typeof(b) Foo() { return b; }
  }
 
  void main()
  {
     int a = 3;
     double b = 3.14;
     mixin .Foo!(a) y;
     mixin .Foo!(b) z;
     assert(y.Foo() == 3);
     assert(z.Foo() == 3.14);
  }
 
 Notice the global scope operators on the mixin instantiations, and the 
 explicit access of y.Foo/z.Foo.
 
 The reason this happens is that the first mixin Foo!(a) y; mixes in the 
 symbol Foo from inside the template.  Then the second mixin attempts to use 
 the local Foo, which is now a mixed-in function, as a template, which fails. 
 So you have to use the global scope operator to access the actual template 
 declaration.  (Actually the first one is optional.)
 
 Then, you can't call y(), because although the function Foo is the same name 
 as the mixin Foo, y is of type mixin Foo!(a), and the compiler doesn't 
 interpret y() as a call to Foo.

Ok, I can see the reasoning behind that now and it does make sense in a strict, pedantic, form ... but OMG that is *such* a horrible mess! I thought programming languages were supposed to make programming easier.
 I was expecting that code to be equivalent to ...

 void main()
 {
    int a = 3;
    double b = 3.14;
    typeof(a) y() { return a; }
    typeof(b) z() { return b; }
    assert(y() == 3);
    assert(z() == 3.14);
 }

It would be great to be able to generate code like that.

And IMHO a lot more intuitive. In fact my first attempt was this ... template Foo(alias a, alias b) { typeof(b) a() { return b; } } . . . mixin Foo!(y,3); assert(y() == 3); because I thought that the documentation meant 'alias' performs lexical symbol substitution rather than whatever it does mean, which I still can't quite interpret. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 4/10/2006 2:26:53 PM
Oct 03 2006
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Derek Parnell wrote:
 On Wed, 4 Oct 2006 00:03:17 -0400, Jarrett Billingsley wrote:
 
 
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:327lkdzeqky1$.11w3vhc3ana9f.dlg 40tude.net...


Anyhow, what am I doing wrong here ...

template Foo(alias b)
{
   typeof(b) Foo() { return b; }
}

void main()
{
   int a = 3;
   double b = 3.14;
   mixin Foo!(a) y;
   mixin Foo!(b) z;
   assert(y() == 3);
   assert(z() == 3.14);
}

Mixins bug me too. Here's the "correct" version of your code:

Thanks for patience.
 template Foo(alias b)
 {
    typeof(b) Foo() { return b; }
 }

 void main()
 {
    int a = 3;
    double b = 3.14;
    mixin .Foo!(a) y;
    mixin .Foo!(b) z;
    assert(y.Foo() == 3);
    assert(z.Foo() == 3.14);
 }

Notice the global scope operators on the mixin instantiations, and the 
explicit access of y.Foo/z.Foo.


I may be wrong, but I think you could do this: # mixin .Foo!(a).Foo y ; # mixin .Foo!(b).Foo z ; # assert(y() == 3); # assert(z() == 3.14); -- Chris Nicholson-Sauls
Oct 03 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Wed, 04 Oct 2006 01:55:45 -0500, Chris Nicholson-Sauls wrote:

 Derek Parnell wrote:
 On Wed, 4 Oct 2006 00:03:17 -0400, Jarrett Billingsley wrote:
 
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:327lkdzeqky1$.11w3vhc3ana9f.dlg 40tude.net...


Anyhow, what am I doing wrong here ...

template Foo(alias b)
{
   typeof(b) Foo() { return b; }
}

void main()
{
   int a = 3;
   double b = 3.14;
   mixin Foo!(a) y;
   mixin Foo!(b) z;
   assert(y() == 3);
   assert(z() == 3.14);
}

Mixins bug me too. Here's the "correct" version of your code:

Thanks for patience.
 template Foo(alias b)
 {
    typeof(b) Foo() { return b; }
 }

 void main()
 {
    int a = 3;
    double b = 3.14;
    mixin .Foo!(a) y;
    mixin .Foo!(b) z;
    assert(y.Foo() == 3);
    assert(z.Foo() == 3.14);
 }

Notice the global scope operators on the mixin instantiations, and the 
explicit access of y.Foo/z.Foo.


I may be wrong, but I think you could do this: # mixin .Foo!(a).Foo y ; # mixin .Foo!(b).Foo z ; # assert(y() == 3); # assert(z() == 3.14);

No such luck ... test.d(10): template instance cannot use local 'a' as template parameter test.d(3): function test.Foo!(a).Foo cannot access frame of function main test.d(10): template instance test.Foo!(a) error instantiating test.d(10): mixin Foo!() is not defined -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 4/10/2006 5:01:36 PM
Oct 04 2006
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:kawtg2nmq5d6$.1dp41k208dts4.dlg 40tude.net...

 No such luck ...

 test.d(10): template instance cannot use local 'a' as template parameter
 test.d(3): function test.Foo!(a).Foo cannot access frame of function main
 test.d(10): template instance test.Foo!(a) error instantiating
 test.d(10): mixin Foo!() is not defined

Almost, you "just" have to split it out into an alias: template Foo(alias b) { typeof(b) Foo() { return b; } } void main() { int a = 2; float b = 3.25; mixin .Foo!(a) tempX; mixin .Foo!(b) tempY; alias tempX.Foo x; alias tempY.Foo y; assert(x() == 2); assert(y() == 3.25); } That works. And is the ugliest thing ever.
Oct 04 2006
prev sibling parent reply Josh Stern <josh_usenet phadd.net> writes:
I think the double use of "Foo" for the template namespace and the
function itself made the example confusing.  The following works
and makes the role of the template and the function and/or class
names clearer (no alias really needed):


import std.stdio;

template FFoo(alias b) {
	
  typeof(b) foo() { return b; } // foo function

  class FooClass {  
	typeof(b) opCall() { return b; } // operator() in FooClass
    }
}

void main() {

int a=5;

mixin .FFoo!(a);  // instantiates foo() and FooClass using local a as parameter	
int y = foo();
writefln(y);

FooClass obj = new FooClass;
y = obj();	
writefln(y);
	
}





On Wed, 04 Oct 2006 17:02:15 +1000, Derek Parnell wrote:

 On Wed, 04 Oct 2006 01:55:45 -0500, Chris Nicholson-Sauls wrote:
 
 Derek Parnell wrote:
 On Wed, 4 Oct 2006 00:03:17 -0400, Jarrett Billingsley wrote:
 
"Derek Parnell" <derek nomail.afraid.org> wrote in message 
news:327lkdzeqky1$.11w3vhc3ana9f.dlg 40tude.net...


Anyhow, what am I doing wrong here ...

template Foo(alias b)
{
   typeof(b) Foo() { return b; }
}

void main()
{
   int a = 3;
   double b = 3.14;
   mixin Foo!(a) y;
   mixin Foo!(b) z;
   assert(y() == 3);
   assert(z() == 3.14);
}

Mixins bug me too. Here's the "correct" version of your code:

Thanks for patience.
 template Foo(alias b)
 {
    typeof(b) Foo() { return b; }
 }

 void main()
 {
    int a = 3;
    double b = 3.14;
    mixin .Foo!(a) y;
    mixin .Foo!(b) z;
    assert(y.Foo() == 3);
    assert(z.Foo() == 3.14);
 }

Notice the global scope operators on the mixin instantiations, and the 
explicit access of y.Foo/z.Foo.


I may be wrong, but I think you could do this: # mixin .Foo!(a).Foo y ; # mixin .Foo!(b).Foo z ; # assert(y() == 3); # assert(z() == 3.14);

No such luck ... test.d(10): template instance cannot use local 'a' as template parameter test.d(3): function test.Foo!(a).Foo cannot access frame of function main test.d(10): template instance test.Foo!(a) error instantiating test.d(10): mixin Foo!() is not defined

Oct 05 2006
parent reply Derek Parnell <derek psyc.ward> writes:
On Thu, 05 Oct 2006 14:28:01 -0500, Josh Stern wrote:

 I think the double use of "Foo" for the template namespace and the
 function itself made the example confusing.  The following works
 and makes the role of the template and the function and/or class
 names clearer (no alias really needed):

I think you have missed my point. I want to mixin the template multiple times, each time giving the resulting statement a different identifier so it can be used in a simple manner. For example, using your 'different' name idea ... import std.stdio; template FFoo(alias b) { typeof(b) foo() { return b; } // foo function } void main() { int a=5; double b = 3.14; // FIRST TIME mixin .FFoo!(a) x; // bring in the statement calling it 'x' writefln( x() ); // SECONND TIME mixin .FFoo!(b) y; // bring it in again but call it 'y' this time. writefln( y() ); } This still fails and yet looks intuitive (to me at least). -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Oct 05 2006
parent reply Josh Stern <josh_usenet phadd.net> writes:
On Fri, 06 Oct 2006 09:04:05 +1000, Derek Parnell wrote:

 On Thu, 05 Oct 2006 14:28:01 -0500, Josh Stern wrote:
 
 I think the double use of "Foo" for the template namespace and the
 function itself made the example confusing.  The following works
 and makes the role of the template and the function and/or class
 names clearer (no alias really needed):

I think you have missed my point. I want to mixin the template multiple times, each time giving the resulting statement a different identifier so it can be used in a simple manner.

Yes, I missed the point that the special difficulty being addressed was trying to avoid a name clash caused by multiple definitions. But even so, mixins and template seem to interact in the way I would expect and I don't see that alias's are really required. You have two good choices here - either use the 'x' and 'y' extra level of namespace idea... import std.stdio; template FFoo(alias b) { typeof(b) foo() { return b; } // foo function } void main() { int a=5; double b = 3.14; // FIRST TIME mixin .FFoo!(a) x; // bring in the statement in the 'x' sub-namespace writefln(x.foo()); // SECOND TIME mixin .FFoo!(b) y; // bring it in in the 'y' sub-namespace. writefln(y.foo()); } ...or just use an extra level of braces around each distinct instantiation... { //First time mixin .FFoo!(a); } { // Second time mixin .FFoo!(b); writefln( foo()); }
 For
 example, using your 'different' name idea ...
 
  import std.stdio;
  template FFoo(alias b) {
   typeof(b) foo() { return b; } // foo function
  }
  void main() {
   int a=5;
   double b = 3.14;
   // FIRST TIME
   mixin .FFoo!(a) x;  // bring in the statement calling it 'x' writefln(
   x() );
   // SECONND TIME
   mixin .FFoo!(b) y;  // bring it in again but call it 'y' this time.
   writefln( y() );
  }
  }
  }
 This still fails and yet looks intuitive (to me at least).

I think of mixin as a smart replacement for macros so I wouldn't expect the above to work.
Oct 05 2006
parent reply Derek Parnell <derek nomail.afraid.org> writes:
On Thu, 05 Oct 2006 18:55:44 -0500, Josh Stern wrote:

   mixin .FFoo!(a) x;  // bring in the statement in the 'x' sub-namespace

Thank you. This was the key information that I didn't pick up from the docs. It is documented but I didn't get it until now. The important passage from the docs is "A mixin has its own scope". I kept on reading that as "the mixin's template has its own scope" but now I understand it is the mixin statement itself that creates a new scope/namespace, and that the "MixinIdentifier" is the optional name one can give to that scope. Then one can use the MixinIdentifier as a namespace qualifier to disambiguate identifiers brought in by the mixin statements. Mind you, this would have been made easier if the 'alias' argument could also have been used to 'set' the identifier declared in the template. In other words it would have been 'smart' for mixin to allow ... template foo(alias a, alias b) { typeof(b) a(b) { . . . } } mixin foo!(Bar, 3); mixin foo!(Qwe, 3.14); to generate code as ... typeof(3) Bar(3) { . . . } typeof(3.14) Qwe(3.14) { . . . } then there would have been no disambiguation required. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 6/10/2006 10:33:50 AM
Oct 05 2006
next sibling parent Josh Stern <josh_usenet phadd.net> writes:
On Fri, 06 Oct 2006 10:43:59 +1000, Derek Parnell wrote:

 On Thu, 05 Oct 2006 18:55:44 -0500, Josh Stern wrote:
 
   mixin .FFoo!(a) x;  // bring in the statement in the 'x' sub-namespace

Thank you. This was the key information that I didn't pick up from the docs. It is documented but I didn't get it until now. The important passage from the docs is "A mixin has its own scope". I kept on reading that as "the mixin's template has its own scope" but now I understand it is the mixin statement itself that creates a new scope/namespace, and that the "MixinIdentifier" is the optional name one can give to that scope. Then one can use the MixinIdentifier as a namespace qualifier to disambiguate identifiers brought in by the mixin statements. Mind you, this would have been made easier if the 'alias' argument could also have been used to 'set' the identifier declared in the template.

You can't use exactly the same name - i.e. mixin .FFoo!(a) a; But you could adopt some convention of related names - i.e. mixin .FFoo!(a) for_a; mixin .FFoo!(b) for_b; for_a.foo(); for_b.foo(); etc.
 In other words it would have been 'smart' for mixin to allow ...
 
  template foo(alias a, alias b)
  {
     typeof(b) a(b) { . . . }
  }
 
  mixin foo!(Bar, 3);
  mixin foo!(Qwe, 3.14);
 
 
 to generate code as ...
 
     typeof(3) Bar(3) { . . . }
     typeof(3.14) Qwe(3.14) { . . . }
 
 then there would have been no disambiguation required.

Oct 05 2006
prev sibling parent Kristian <kjkilpi gmail.com> writes:
On Fri, 06 Oct 2006 03:43:59 +0300, Derek Parnell  
<derek nomail.afraid.org> wrote:

 On Thu, 05 Oct 2006 18:55:44 -0500, Josh Stern wrote:

   mixin .FFoo!(a) x;  // bring in the statement in the 'x' sub-namespace

Thank you. This was the key information that I didn't pick up from the docs. It is documented but I didn't get it until now. The important passage from the docs is "A mixin has its own scope". I kept on reading that as "the mixin's template has its own scope" but now I understand it is the mixin statement itself that creates a new scope/namespace, and that the "MixinIdentifier" is the optional name one can give to that scope. Then one can use the MixinIdentifier as a namespace qualifier to disambiguate identifiers brought in by the mixin statements. Mind you, this would have been made easier if the 'alias' argument could also have been used to 'set' the identifier declared in the template. In other words it would have been 'smart' for mixin to allow ... template foo(alias a, alias b) { typeof(b) a(b) { . . . } } mixin foo!(Bar, 3); mixin foo!(Qwe, 3.14); to generate code as ... typeof(3) Bar(3) { . . . } typeof(3.14) Qwe(3.14) { . . . } then there would have been no disambiguation required.

Yep, that would be very useful. This feature, i.e. an ability to declare custom identifiers (or part of them) in templates, has been suggested before (not surprisingly). Lets hope that it will be implemented someday. *wink*wink* ;)
Oct 06 2006