Thread overview
Mixin template confusion / compiler error.
Jan 19, 2017
Chris Katko
Jan 19, 2017
Chris Katko
Jan 19, 2017
Ali Çehreli
Jan 19, 2017
Chris Katko
Jan 19, 2017
Daniel N
Jan 19, 2017
Ali Çehreli
Jan 19, 2017
Ali Çehreli
January 19, 2017
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


January 19, 2017
Addendum:

Writing the following:

writeln(mixin(sizer2D!()));

simply dumps 64 to stdout.



What's going on here? Have I run into a compiler bug?
January 19, 2017
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

January 19, 2017
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.


January 19, 2017
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;

January 19, 2017
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

January 19, 2017
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