www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - static if and templates

reply Oliver <oliver.ruebenkoenig web.de> writes:
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) );
}
Sep 27 2007
parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
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)) ); }
Sep 27 2007
parent reply Oliver <oliver.ruebenkoenig BLUBweb.de> writes:
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)) );
 }
 

Sep 27 2007
parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 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
Sep 27 2007
parent reply Don Clugston <dac nospam.com.au> writes:
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.
Sep 27 2007
parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
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])); }
Sep 27 2007
parent Oliver <oliver.ruebenkoenig BLUBweb.de> writes:
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) );
}
Sep 28 2007