Thread overview
Bug or am I getting things wrong
Jan 07, 2016
Q. Schroll
Jan 07, 2016
John Colvin
Jan 07, 2016
Ali Çehreli
January 07, 2016
In the listing below the commented line should do exactly the same thing as the one above.

/// DimArr!(i, T) ==> T[][]...[] i times.
template DimArr(size_t i, T)
{
    static if (i == 0)  alias DimArr = T;
    else                alias DimArr = DimArr!(i - 1, T)[];
}


struct Array(T, size_t rk)
    if (rk > 1)
{
    private size_t[rk] dims;
    /+ ... +/
    auto toNestedArray() const
    {
        import std.range : iota;
        import std.format : format;
        enum dimsIndexed = `%(dims[%d]%|, %)`.format(dims.length.iota);
        auto result = mixin(`new DimArr!(rk, T)(` ~ dimsIndexed ~ `)`);
     // auto result = new DimArr!(rk, T)(mixin(dimsIndexed)));
        /+ ... +/
        return result;
    }
}

The one above does exactly what I want, but the lower one only uses the last dimension for some reason. I found out by using these pragmas

    pragma(msg, "'", dimsIndexed, "'");
    pragma(msg, ( new DimArr!(rk, T) ( mixin(dimsIndexed) ) ).stringof);

Can someone please tell me what I'm getting wrong here, or is this a bug?
January 07, 2016
On Thursday, 7 January 2016 at 07:51:05 UTC, Q. Schroll wrote:
> In the listing below the commented line should do exactly the same thing as the one above.
>
> /// DimArr!(i, T) ==> T[][]...[] i times.
> template DimArr(size_t i, T)
> {
>     static if (i == 0)  alias DimArr = T;
>     else                alias DimArr = DimArr!(i - 1, T)[];
> }
>
>
> struct Array(T, size_t rk)
>     if (rk > 1)
> {
>     private size_t[rk] dims;
>     /+ ... +/
>     auto toNestedArray() const
>     {
>         import std.range : iota;
>         import std.format : format;
>         enum dimsIndexed = `%(dims[%d]%|, %)`.format(dims.length.iota);
>         auto result = mixin(`new DimArr!(rk, T)(` ~ dimsIndexed ~ `)`);
>      // auto result = new DimArr!(rk, T)(mixin(dimsIndexed)));
>         /+ ... +/
>         return result;
>     }
> }
>
> The one above does exactly what I want, but the lower one only uses the last dimension for some reason. I found out by using these pragmas
>
>     pragma(msg, "'", dimsIndexed, "'");
>     pragma(msg, ( new DimArr!(rk, T) ( mixin(dimsIndexed) ) ).stringof);
>
> Can someone please tell me what I'm getting wrong here, or is this a bug?

Wow, that's a new reason to hate the comma operator even more than I did before!

The expression that you are mixing in is actually a sequence of sub-expressions seperated by the comma operator, which means each expression is evaluated and the last one is returned. Remember, mixins are not textual substitution like C macros. Normally speaking you get error messages if you forget that, and that's ok, but here the evil comma operator made a mess of things.

Here's one way to achieve what you want:

/// DimArr!(i, T) ==> T[][]...[] i times.
template DimArr(size_t i, T)
{
    static if (i == 0)
		alias DimArr = T;
    else
		alias DimArr = DimArr!(i - 1, T)[];
}

template Repeat(T, size_t N)
{
	import std.meta : AliasSeq;
	static if (N == 0)
		alias Repeat = AliasSeq!();
	else
		alias Repeat = AliasSeq!(T, Repeat!(T, N-1));
}

auto toTuple(T, size_t N)(T[N] arr)
{
	import std.typecons : Tuple;
	import std.traits : Unqual;
	Tuple!(Repeat!(Unqual!T, N)) tup;
	foreach(i, _; tup)
		tup[i] = arr[i];
	return tup;
}

struct Array(T, size_t rk)
    if (rk > 1)
{
    private size_t[rk] dims;
    /+ ... +/
    auto toNestedArray() const
    {
        auto result = new DimArr!(rk, T)(dims.toTuple.expand);
        /+ ... +/
        return result;
    }
}
January 07, 2016
On 01/06/2016 11:51 PM, Q. Schroll wrote:
> In the listing below the commented line should do exactly the same thing
> as the one above.
>
> /// DimArr!(i, T) ==> T[][]...[] i times.
> template DimArr(size_t i, T)
> {
>      static if (i == 0)  alias DimArr = T;
>      else                alias DimArr = DimArr!(i - 1, T)[];
> }
>
>
> struct Array(T, size_t rk)
>      if (rk > 1)
> {
>      private size_t[rk] dims;
>      /+ ... +/
>      auto toNestedArray() const
>      {
>          import std.range : iota;
>          import std.format : format;
>          enum dimsIndexed = `%(dims[%d]%|, %)`.format(dims.length.iota);
>          auto result = mixin(`new DimArr!(rk, T)(` ~ dimsIndexed ~ `)`);
>       // auto result = new DimArr!(rk, T)(mixin(dimsIndexed)));
>          /+ ... +/
>          return result;
>      }
> }
>
> The one above does exactly what I want, but the lower one only uses the
> last dimension for some reason. I found out by using these pragmas
>
>      pragma(msg, "'", dimsIndexed, "'");
>      pragma(msg, ( new DimArr!(rk, T) ( mixin(dimsIndexed) ) ).stringof);
>
> Can someone please tell me what I'm getting wrong here, or is this a bug?

I don't see any difference with dmd v2.069.2. Both lines print the following:

'dims[0], dims[1], dims[2], dims[3], dims[4], dims[5], dims[6], dims[7], dims[8], dims[9]'
new int[][][][][][][][][][](this.dims[9])

Here is the program:

/// DimArr!(i, T) ==> T[][]...[] i times.
template DimArr(size_t i, T)
{
    static if (i == 0)  alias DimArr = T;
    else                alias DimArr = DimArr!(i - 1, T)[];
}


struct Array(T, size_t rk)
    if (rk > 1)
{
    private size_t[rk] dims;
    /+ ... +/
    auto toNestedArray() const
    {
        import std.range : iota;
        import std.format : format;
        enum dimsIndexed = `%(dims[%d]%|, %)`.format(dims.length.iota);
        auto result = mixin(`new DimArr!(rk, T)(` ~ dimsIndexed ~ `)`);
        // auto result = new DimArr!(rk, T)(mixin(dimsIndexed));
        /+ ... +/

    pragma(msg, "'", dimsIndexed, "'");
    pragma(msg, ( new DimArr!(rk, T) ( mixin(dimsIndexed) ) ).stringof);

        return result;
    }
}

void main() {
    auto a = Array!(int, 10)();
    import std.stdio;
    writeln(a.toNestedArray());
}

Ali