www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mixin template confusion / compiler error.

reply Chris Katko <ckatko gmail.com> writes:
I've tried to narrow this down to the minimum code that exhibits 
the problem.

When I use a mixin, to supply the parameters for a template, it 
works with ONE argument, but NOT TWO.

template sizer2D() // no params here for simplicity
	{
	const char [] sizer2D = "64,64";	
	}	
template sizer1D()
	{
	const char [] sizer1D = "64";	
	}	
	
class why_t ()
	{
	array_t!(64,64) case1;	// works
	array_t!(mixin(sizer2D!())) case2; // FAILS (error below)

	array2_t!(64) case3; // works
	array2_t!(mixin(sizer1D!())) case4; // works

	array3_t!(64) case5; // works
	array3_t!(mixin(sizer2D!())) case6; // WORKS using ONE ARGUMENT 
method using default parameter for height (see class)
	}
	
class array_t (int width, int height)
	{
	int [width][height] data;
	}
class array2_t (int width)
	{
	int [width][width] data;
	}
class array3_t (int width, int height=width) //note default param
	{
	int [width][height] data;
	}



The error I get is:

Error: template instance array_t!64 does not match template 
declaration array_t(int width, int height)

Error: template instance a5test.why_t!() error instantiating

And the strange thing is, it's like it's only outputting ONE of 
the two numbers. If it were outputting any other gibberish, it 
shouldn't compile at all. And I'm not misplacing the 1D vs 2D 
function names because originally there was NO 1D version at all. 
It was just the 2D and it wouldn't compile.

Is there any way to get a PRINTOUT of the mixin code upon failure 
to see what it's actually trying to compile?

---------


I'm using LDC2:

LDC - the LLVM D compiler (e9b2b4):
   based on DMD v2.068.2 and LLVM 3.5.0
Jan 19 2017
next sibling parent Chris Katko <ckatko gmail.com> writes:
Addendum:

Writing the following:

writeln(mixin(sizer2D!()));

simply dumps 64 to stdout.



What's going on here? Have I run into a compiler bug?
Jan 19 2017
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/19/2017 12:03 AM, Chris Katko wrote:

 template sizer2D() // no params here for simplicity
     {
     const char [] sizer2D = "64,64";
     }
     array_t!(mixin(sizer2D!())) case2; // FAILS (error below)
 Error: template instance array_t!64 does not match template declaration
 array_t(int width, int height)
The comma operator strikes back but this time it's caught. :) The clue was exposed because my compilation has the following dmd flag: -de show use of deprecated features as errors (halt compilation) According to spec, "The text contents of the string must be compilable as a valid StatementList, and is compiled as such.": https://dlang.org/spec/statement.html#mixin-statement So, "64,64" is mixed in as two expressions around a comma operator and it gets the value 64. Ali
Jan 19 2017
parent reply Chris Katko <ckatko gmail.com> writes:
Thank you!

So:

1 - Is there any way TO get the output 64,64? It seems like being 
able to get a comma out of a mixin is a useful feature.

2 - Is this very non-standard / unrecommended practice and 
there's a much better way to do this?

For example, in my actual code, I have an enumerator:

enum MAP_SIZE
     {
     PLANET = 2048,
     SHIP = 256,
     SHUTTLE = 64,
     (etc)
     } //this could also be translated to an array lookup. ala 
SHIP = 0, SHUTTLE = 1, etc. with an array holding the sizes.

and then I pass MAP_SIZE, into a map class, which then builds 
layers into that map based on the MAP_SIZE. The layers are 
statically sized at compile-time by translating a given MAP_SIZE 
down to the actual required dimensions.

So in plain English: Based on a MAP_SIZE, the inner structures 
are all sized appropriately at compile-time.

So, for example:

map_t!(MAP_SIZE.SHIP) x;

goes into

map_t(MAP_SIZE s)
     {
     layer_t!(mixin(sizer2D!(s))) layer;
     }

which becomes

map_t(MAP_SIZE s)
     {
     layer_t!(64,64) layer;
     }

and in layer_t:

layer_t(int width, int height)
     {
     int [width][height] data;
     }


Is there a different way to go about this? Should I be building 
some sort of function inside a template that "decides" / 
"translates" a passed template parameter MAP_SIZE to width and 
height values?

I guess I could try putting the mixin inside layer_t and put the 
values into the square brackets, instead of commas. But again, 
"no commas" seem so arbitrary from an abstract, novice 
perspective. What if I was pre-processing English statements 
which include commas?

Thank you for your assistance. I appreciate it.
Jan 19 2017
next sibling parent Daniel N <no public.email> writes:
On Thursday, 19 January 2017 at 08:41:53 UTC, Chris Katko wrote:
 Thank you!

 So:

 1 - Is there any way TO get the output 64,64?
Would this work for you? import std.meta; alias sizer1D = AliasSeq!(64); alias sizer2D = AliasSeq!(64,64); array_t!sizer2D caseX; array2_t!sizer1D caseY;
Jan 19 2017
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/19/2017 12:41 AM, Chris Katko wrote:

 1 - Is there any way TO get the output 64,64?
You can mixin the entire statement. I used the ~ operator but you can use format() or the return value of a function as well: mixin("array_t!(" ~ sizer2D!() ~ ") case2;"); // ... mixin("array3_t!(" ~ sizer2D!() ~ ") case6;"); With function call: mixin(makeDeclaration(/* ... */));
 2 - Is this very non-standard / unrecommended practice and there's a
 much better way to do this?
There are other options like using literals like 64. Perhaps an AliasSeq!(64, 64) could be useful.
 enum MAP_SIZE
     {
     PLANET = 2048,
     SHIP = 256,
     SHUTTLE = 64,
     (etc)
     } //this could also be translated to an array lookup. ala SHIP = 0,
 SHUTTLE = 1, etc. with an array holding the sizes.

 and then I pass MAP_SIZE, into a map class, which then builds layers
 into that map based on the MAP_SIZE. The layers are statically sized at
 compile-time by translating a given MAP_SIZE down to the actual required
 dimensions.

 So in plain English: Based on a MAP_SIZE, the inner structures are all
 sized appropriately at compile-time.
I think the best way of doing this is by producing the entire code as string but look at the implementation of std.bitmanip.bitfields to see how it's actually a mixin template than contains an enum, I think to prevent name-polluting the scope that it's mixed in.
 "no commas" seem so arbitrary from an abstract, novice
 perspective.
I think AliasSeq is your best bet in that case.
 What if I was pre-processing English statements which include
 commas?
Of course you can do that as strings but mixed-in code must obey the spec and it must be "a valid StatementList". In other words, D's string mixins are the same as C's macros. Ali
Jan 19 2017
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/19/2017 01:06 AM, Ali Çehreli wrote:

 In other words, D's string
 mixins are the same as C's macros.
I was testing you! :p I meant "NOT the same as". :p Ali
Jan 19 2017