Thread overview
Error on recursive alias
Aug 25, 2013
Johan Mollevik
Aug 25, 2013
bearophile
Aug 25, 2013
Johan Mollevik
Aug 25, 2013
bearophile
Aug 25, 2013
Johan Mollevik
Aug 25, 2013
Johan Mollevik
Aug 25, 2013
Ali Çehreli
Aug 25, 2013
Johan Mollevik
August 25, 2013
I have some code from a couple of years ago that I'm trying to update to modern D.

I was first using the gdc compiler in debian stable which seems based on DMD 2.055 but that caused somthing that looks like memmory coruption.

Using the newer gdc compiler in debian sid (based on DMD 2.062 i think) I run into this error instead.

util.d:23: Error: alias util.foreachType!(uint[4LU][4LU]).foreachType recursive alias declaration

This is for code that have worked previously looking like this

template foreachType(T)
{
        static if(is(opApplyType!(T) V))
        {
                static if(is(opApplyType!(V[$-1])))
                        alias Tuple!(V[0..$-1],foreachType!(V[$-1]))
foreachType;
                else
                        alias V foreachType;
        }
        else
        {
                pragma(msg,"Failed to resolve type ");
                static assert(0,opApplyType!(T));
        }
}

I can post all the source code if anyone is interested

What my ultimate goal is is to resurect my opApplyN function allowing me to do things like this

uint[4][4] block;
foreach(x,y,v;opApplyN(block))
	printf("%d %d %d\n",x,y,v);


If anyone know a more convinient way to achive that that would be helpfull as well.
August 25, 2013
Johan Mollevik:

> What my ultimate goal is is to resurect my opApplyN function allowing
> me to do things like this
>
> uint[4][4] block;
> foreach(x,y,v;opApplyN(block))
> 	printf("%d %d %d\n",x,y,v);

What are x y and v?

Bye,
bearophile
August 25, 2013
bearophile wrote:

> Johan Mollevik:
> 
>> What my ultimate goal is is to resurect my opApplyN function
>> allowing
>> me to do things like this
>>
>> uint[4][4] block;
>> foreach(x,y,v;opApplyN(block))
>> printf("%d %d %d\n",x,y,v);
> 
> What are x y and v?
> 
> Bye,
> bearophile

x and y are the two dimensional indices into the 4x4 array block and v is the vallue at block[y][x]
August 25, 2013
Johan Mollevik:

> x and y are the two dimensional indices into the 4x4 array block and v
> is the vallue at block[y][x]

OK. Something like this?


import std.stdio, std.typecons;

struct NaturalScan(T) {
    T[][] data;
    size_t r, c;

    @property bool empty() const pure nothrow {
        return r == data.length;
    }

    @property Tuple!(size_t, size_t, T) front()
    const pure nothrow {
        return typeof(return)(r, c, data[r][c]);
    }

    void popFront() pure nothrow {
        c = (c + 1) % data[r].length;
        if (c == 0)
            r++;
    }
}

NaturalScan!T naturalScan(T)(T[][] m) {
    return typeof(return)(m);
}

void main() {
    auto mat = [[10, 20], [30, 40, 50], [60, 70]];
    foreach (r, c, v; mat.naturalScan)
        writefln("%d %d %d", r, c, v);
}


Bye,
bearophile
August 25, 2013
bearophile wrote:

> Johan Mollevik:
> 
>> x and y are the two dimensional indices into the 4x4 array
>> block and v
>> is the vallue at block[y][x]
> 
> OK. Something like this?
> 
> 
> import std.stdio, std.typecons;
> 
> struct NaturalScan(T) {
>      T[][] data;
>      size_t r, c;
> 
>      @property bool empty() const pure nothrow {
>          return r == data.length;
>      }
> 
>      @property Tuple!(size_t, size_t, T) front()
>      const pure nothrow {
>          return typeof(return)(r, c, data[r][c]);
>      }
> 
>      void popFront() pure nothrow {
>          c = (c + 1) % data[r].length;
>          if (c == 0)
>              r++;
>      }
> }
> 
> NaturalScan!T naturalScan(T)(T[][] m) {
>      return typeof(return)(m);
> }
> 
> void main() {
>      auto mat = [[10, 20], [30, 40, 50], [60, 70]];
>      foreach (r, c, v; mat.naturalScan)
>          writefln("%d %d %d", r, c, v);
> }
> 
> 
> Bye,
> bearophile

That looks like it might work for 2 dimensions and as that is the use case I have right now I might settle for that. (and I can add more overloads manually if needed)

The original code was genereal enough to handle any number of dimensions thou.

Bassically this would work like this

uint[][][] array=...

foreach(x,v;opApplyN(array)){//using only one index (x)
	//v has type uint[][]
}


foreach(x,y,v;opApplyN(array)){//using two indeces (x,y)
	//v has type uint[]
}


foreach(x,y,z,v;opApplyN(array)){//using three index (x,y,z)
	//v has type uint
}

So if someone know anything of why I get the error on recursive aliases I might try to get that working again otherwise I might try your code as it is enough for now

Thnks for the help by the way
August 25, 2013
Johan Mollevik wrote:

> bearophile wrote:
> 
>> Johan Mollevik:
>> 
>>> x and y are the two dimensional indices into the 4x4 array
>>> block and v
>>> is the vallue at block[y][x]
>> 
>> OK. Something like this?
>> 
>> 
>> import std.stdio, std.typecons;
>> 
>> struct NaturalScan(T) {
>>      T[][] data;
>>      size_t r, c;
>> 
>>      @property bool empty() const pure nothrow {
>>          return r == data.length;
>>      }
>> 
>>      @property Tuple!(size_t, size_t, T) front()
>>      const pure nothrow {
>>          return typeof(return)(r, c, data[r][c]);
>>      }
>> 
>>      void popFront() pure nothrow {
>>          c = (c + 1) % data[r].length;
>>          if (c == 0)
>>              r++;
>>      }
>> }
>> 
>> NaturalScan!T naturalScan(T)(T[][] m) {
>>      return typeof(return)(m);
>> }
>> 
>> void main() {
>>      auto mat = [[10, 20], [30, 40, 50], [60, 70]];
>>      foreach (r, c, v; mat.naturalScan)
>>          writefln("%d %d %d", r, c, v);
>> }
>> 
>> 
>> Bye,
>> bearophile
> 
> That looks like it might work for 2 dimensions and as that is the use case I have right now I might settle for that. (and I can add more overloads manually if needed)
> 
> The original code was genereal enough to handle any number of dimensions thou.
> 
> Bassically this would work like this
> 
> uint[][][] array=...
> 
> foreach(x,v;opApplyN(array)){//using only one index (x)
> //v has type uint[][]
> }
> 
> 
> foreach(x,y,v;opApplyN(array)){//using two indeces (x,y)
> //v has type uint[]
> }
> 
> 
> foreach(x,y,z,v;opApplyN(array)){//using three index (x,y,z)
> //v has type uint
> }
> 
> So if someone know anything of why I get the error on recursive
aliases
> I might try to get that working again otherwise I might try your code as it is enough for now
> 
> Thnks for the help by the way

Hmm, your solution does not work with static arrays it seems, will se if I can sort that out

August 25, 2013
On 08/25/2013 09:23 AM, Johan Mollevik wrote:

> Hmm, your solution does not work with static arrays it seems, will se
> if I can sort that out

Probably due to the fact that static arrays cannot be InputRanges because they cannot lose elements by popFront(). A slice to the entire array is an InputRange though:

    foreach (e; myStaticArray)      // compilation error

    foreach (e; myStaticArray[])    // works

Ali

August 25, 2013
Ali Çehreli wrote:

> On 08/25/2013 09:23 AM, Johan Mollevik wrote:
> 
>  > Hmm, your solution does not work with static arrays it seems, will
se
>  > if I can sort that out
> 
> Probably due to the fact that static arrays cannot be InputRanges because they cannot lose elements by popFront(). A slice to the
entire
> array is an InputRange though:
> 
>      foreach (e; myStaticArray)      // compilation error
> 
>      foreach (e; myStaticArray[])    // works
> 
> Ali

I accutally got my original code to work just now. I made a mistake when translating typeof(T[0]) into more modern code. That caused supprising errors.

Pasting the code bellow if anyone is interested (can probably be shortened), thanks for the help and quick response.


import std.traits;
import std.conv;
import std.metastrings;

template Tuple(T...)
{
        alias T Tuple;
}
template opApplyType(T)
{
        static if(isArray!T)
                alias Tuple!(size_t,ForeachType!T) opApplyType;
        else static if(isAssociativeArray!T)
                alias Tuple!(typeof(T.keys)[0],typeof(T.values)[0])
opApplyType;
        else static if(hasMember!(T,"opApply"))
                alias ParameterTypeTuple!(typeof(&T.opApply))
opApplyType;
}
template foreachType(T)
{
        static if(is(opApplyType!(T) V))
        {
                static if(is(opApplyType!(V[$-1])))
                        alias Tuple!(V[0..$-1],foreachType!(V[$-1]))
foreachType;
                else
                        alias V foreachType;
        }
        else
        {
                pragma(msg,"Failed to resolve type ");
                static assert(0,opApplyType!(T));
        }
}
template DgArgs(T...)
{
        static if(T.length)
                const char[] DgArgs="ref "~T[0].stringof~","~DgArgs!
(T[1..$]);
        else
                const char[] DgArgs="";
}
template DgType(T...)
{
        mixin("alias int delegate("~DgArgs!(T)~") Type;");
}
template opApplyParams(int i)
{
        static if(i==0)
                const char[] opApplyParams="";
        else
                const char[]
opApplyParams=",p"~to!string(i)~opApplyParams!(i-1);
}
template opApplyRest(int i)
{
        const char[] opApplyRest="foreach(p"~opApplyParams!
(i)~";opApplyN(v))"
                                ~"\n\tif(auto r=dg(i,p"~opApplyParams!
(i)~"))"
                                ~"\n\t\treturn r;";
}
struct opApplyContext(T)
{
        alias foreachType!(T) FT;
        mixin DgType!(FT) DG;
        T* a;
        int opApply(DG.Type dg)
        {
                //consider recursive mixin of delegate function
                //writefln("Begin opApplyN: ",DG.Type.stringof);
                static if(isArray!T)
                {
                        //pragma(msg,"array");
                        static if(is(opApplyType!(typeof((*a)[0])) V))
                        {
                                //pragma(msg,"branch");
                                foreach(i,v;*a)
                                {
                                        //pragma(msg,V.stringof);
                                        //pragma(msg,DG.Type.stringof);
                                        //pragma(msg,typeof(&opApplyN(v).opApply).stringof);
                                        //pragma(msg,opApplyRest!
(FT.length-2));
                                        mixin(opApplyRest!
(FT.length-2));
                                }
                        }
                        else
                        {
                                //pragma(msg,"leaf");
                                foreach(i,v;*a)
                                        if(auto r=dg(i,v))
                                                return r;
                        }
                }
                else static if(isAssociativeArray!(T))
                {
                        pragma(msg,"hash");
                        static assert(0,"Not Implemented");
                }
                else static if(hasMember!(T,"opApply"))
                {
                        pragma(msg,"opApply");
                        static assert(0,"Not Implemented");
                }
                else
                {
                        pragma(msg,"else");
                        static assert(0,"Not Implemented");
                }
                return 0;
        }
}
opApplyContext!(T) opApplyN(T)(T c)
{
        opApplyContext!(T) t;
        t.a=&c;
        return t;
}
opApplyContext!(T) opApplyN(T:T*)(T* c)
{
        opApplyContext!(T) t;
        t.a=c;
        return t;
}