Thread overview
static if and templates
Sep 27, 2007
Oliver
Sep 27, 2007
Christian Kamm
Sep 27, 2007
Oliver
Sep 27, 2007
Christian Kamm
Sep 27, 2007
Don Clugston
Sep 27, 2007
Christian Kamm
Sep 28, 2007
Oliver
September 27, 2007
Hi,

in the function isMatrix I would like to access the function isArray. Unfortunately, this does not work, even though if I use the definition of isArray directly it does work.

How could I write the code using isArray? Thanks for any hints. Oliver

------------------

import std.stdio;

bool isArray(T)(T expr){
    return (expr.mangleof)[0] == 'A';
}

bool isMatrix(T)(T expr){
    static if ( (expr.mangleof)[0] == 'A' ) // works
    //static if ( isArray(expr) )  // does NOT work
        return (expr.mangleof)[1] == 'A';
    else
        return false;
}

void main () {
    double s = 1.;
    double[] v = [1.,2.];
    double[][] m = [[1.,2.]];

    writefln("s: ", isArray(s), " ", isMatrix(s) );
    writefln("v: ", isArray(v), " ", isMatrix(v) );
    writefln("m: ", isArray(m), " ", isMatrix(m) );
}

September 27, 2007
Oliver wrote:

> bool isArray(T)(T expr){
> return (expr.mangleof)[0] == 'A';
> }
> 
> bool isMatrix(T)(T expr){
> static if ( (expr.mangleof)[0] == 'A' ) // works
> //static if ( isArray(expr) )  // does NOT work
> return (expr.mangleof)[1] == 'A';
> else
> return false;
> }

Static if requires the condition to be evaluated at compile time, but expr is a run time construct. You can make these two compile-time evaluateable by switching to templates:

---
import std.stdio;

template isArray(T){
    const isArray = (T.mangleof)[0] == 'A';
}

template isMatrix(T){
    static if ( isArray!(T) )
        const isMatrix = (T.mangleof)[1] == 'A';
    else
        const isMatrix = false;
}

void main () {
    double s = 1.;
    double[] v = [1.,2.];
    double[][] m = [[1.,2.]];

    writefln("s: ", isArray!(typeof(s)), " ", isMatrix!(typeof(s)) );
    writefln("v: ", isArray!(typeof(v)), " ", isMatrix!(typeof(v)) );
    writefln("m: ", isArray!(typeof(m)), " ", isMatrix!(typeof(m)) );
}

September 27, 2007
Christian,

thank you for your reply and your code.

> Static if requires the condition to be evaluated at compile time, but expr is a run time construct. You can make these two compile-time evaluateable by switching to templates:

what i do not understand is the following: if expr is a runtime construct, how come  expr.mangleof works? for this to work (in my beginner thinking) the compiler takes, say m, from main and inserts it into expr.mangleof. Now, why is it not possible for the compile to insert the expr into isArray? I think there is some fundamental thing i don't understand. Any wisdom you can share?

Oliver

> 
> ---
> import std.stdio;
> 
> template isArray(T){
>     const isArray = (T.mangleof)[0] == 'A';
> }
> 
> template isMatrix(T){
>     static if ( isArray!(T) )
>         const isMatrix = (T.mangleof)[1] == 'A';
>     else
>         const isMatrix = false;
> }
> 
> void main () {
>     double s = 1.;
>     double[] v = [1.,2.];
>     double[][] m = [[1.,2.]];
> 
>     writefln("s: ", isArray!(typeof(s)), " ", isMatrix!(typeof(s)) );
>     writefln("v: ", isArray!(typeof(v)), " ", isMatrix!(typeof(v)) );
>     writefln("m: ", isArray!(typeof(m)), " ", isMatrix!(typeof(m)) );
> }
> 

September 27, 2007
> what i do not understand is the following: if expr is a runtime construct, how come  expr.mangleof works? for this to work (in my beginner thinking) the compiler takes, say m, from main and inserts it into expr.mangleof. Now, why is it not possible for the compile to insert the expr into isArray? I think there is some fundamental thing i don't understand. Any wisdom you can share?

Well, I'm pretty sure expr.mangleof becomes typeof(expr).mangleof, so

---
class A {}
class B : A {}

A a = new B;
writefln(a.mangleof);
---

Would give you the mangled name of A (compile time type) and not of B.

By the way, a more conventional way of writing your isArray and isMatrix functions would be

---
template isArray(T){
  static if(is(T U : U[]))
    const isArray = true;
  else
    const isArray = false;
}

template isMatrix(T){
  static if(is(T U : U[][]))
    const isMatrix = true;
  else
    const isMatrix = false;
}
---

And finally, I don't recommend using T[][] as a matrix type: it's literally an array of arrays, so each row mat[i] does not even need to have the same length and you won't get very good performance.

So, unless that's what you want, I recommend looking through the projects at dsource for implementations of vectors and matrices - I think there are several.

Cheers,
Christian
September 27, 2007
Christian Kamm wrote:
>> what i do not understand is the following: if expr is a runtime construct,
>> how come  expr.mangleof works? for this to work (in my beginner thinking)
>> the compiler takes, say m, from main and inserts it into expr.mangleof.
>> Now, why is it not possible for the compile to insert the expr into
>> isArray? I think there is some fundamental thing i don't understand. Any
>> wisdom you can share?
> 
> Well, I'm pretty sure expr.mangleof becomes typeof(expr).mangleof, so
> 
> ---
> class A {}
> class B : A {}
> 
> A a = new B;
> writefln(a.mangleof);
> ---
> 
> Would give you the mangled name of A (compile time type) and not of B.
> 
> By the way, a more conventional way of writing your isArray and isMatrix
> functions would be
> 
> ---
> template isArray(T){
>   static if(is(T U : U[]))
>     const isArray = true;
>   else
>     const isArray = false;
> }

If you use:
   static if (is(typeof(T[0]))
it will work for user-defined types.
September 27, 2007
Don Clugston wrote:

>> template isArray(T){
>>   static if(is(T U : U[]))
>>     const isArray = true;
>>   else
>>     const isArray = false;
>> }
> 
> If you use:
>     static if (is(typeof(T[0]))
> it will work for user-defined types.

Indeed that will accept anything that provides opIndex. You can check for opSlice and the rest in a similar way, if your code requires them to be available. With these checks, you can even skip the static if:

template hasIndexAndSlice(T) {
  const bool hasIndexAndSlice = is(typeof(T[0])) && is(typeof(T[0..0]));
}

September 28, 2007
Christian and Don,

thanks for you help. Here is what i do now.
1) it is modular
2) is dose not need the clumsy yx!() notation.

thanks again,
oliver

-----------
import std.stdio;

bool isIndexed(T)(T) {
    return is( typeof(T[0]) );
}

bool isDoubleIndexed(T)(T) {
    return is( typeof(T[0][0]) );
}

bool isSliced(T)(T) {
    return is( typeof(T[0..0]) );
}

bool isArray(T)(T expr) {
    return isIndexed(expr);
}

bool isMatrix(T)(T expr) {
    return isIndexed(expr) && isDoubleIndexed(expr);
}

bool isBlubb(T)(T expr) {
    return !isMatrix(expr);
}

void main () {
    double s = 1.;
    double[] v = [1.,2.];
    double[][] m = [[1.,2.]];

    writefln("s: ", isArray(s), " ", isMatrix(s) );
    writefln("v: ", isArray(v), " ", isMatrix(v) );
    writefln("m: ", isArray(m), " ", isMatrix(m) );
    writefln("b: ", isBlubb(v), " ", isBlubb(m) );
}