digitalmars.D - typedef in D2
- bearophile (237/237) Apr 21 2010 I think a recent discussion about typedef has decided to remove the type...
- Trass3r (6/8) Apr 22 2010 Yeah me too.
I think a recent discussion about typedef has decided to remove the typedef and
keep only the alias (if I am wrong, then only the last part of this can be
useful).
In that thread people have said they find typedef useless, but I keep finding
it useful even in partially OOP code too.
In the D.learn group there was a long thread (that's not closed yet, I have one
more answer to add) about some C++ code ported to D (the OP programmer is a
newbie D programmer):
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.learn&article_id=19449
This is the last D version of his program, that I have cleaned up a little in
successive stages (and there are some more things to fix left):
version (Tango) {
    import tango.stdc.stdio: printf;
    import tango.math.Math: sqrt, pow;
} else {
    import std.stdio: printf;
    import std.math: sqrt, pow;
}
struct FastRandom {
    uint kiss_x = 1;
    uint kiss_y = 2;
    uint kiss_z = 4;
    uint kiss_w = 8;
    uint kiss_carry = 0;
    uint kiss_k, kiss_m;
    void seed(uint seed) {
        kiss_x = seed | 1;
        kiss_y = seed | 2;
        kiss_z = seed | 4;
        kiss_w = seed | 8;
        kiss_carry = 0;
    }
    uint randUint() {
        kiss_x = kiss_x * 69069 + 1;
        kiss_y ^= kiss_y << 13;
        kiss_y ^= kiss_y >> 17;
        kiss_y ^= kiss_y << 5;
        kiss_k = (kiss_z >> 2) + (kiss_w >> 3) + (kiss_carry >> 2);
        kiss_m = kiss_w + kiss_w + kiss_z + kiss_carry;
        kiss_z = kiss_w;
        kiss_w = kiss_m;
        kiss_carry = kiss_k >> 30;
        return kiss_x + kiss_y + kiss_w;
    }
    double random() {
        return this.randUint() / (uint.max + 1.0);
    }
    double uniform(double a, double b) {
        double r = cast(double)this.randUint() / (uint.max + 1.0);
        return a + (b - a) * r;
    }
}
struct Rating {
    uint user, object;
    double value;
}
abstract class ReputationAlgorithm {
    this() {}
}
typedef Rating[] TyRatings;
typedef double[] TyReputationUser;
typedef double[] TyReputationObject;
final class Yzlm : ReputationAlgorithm {
    double beta;
    double convergenceRequirement;
    double errorMin;
//    uint[] userLinks; // commented out because for now it
                        // has a constant value for all users
    double[] weightSum;
    TyReputationObject oldReputationObject;
    double objectReputationUpdate(TyRatings ratings,
                                  TyReputationUser reputationUser,
                                  ref TyReputationObject reputationObject) {
        double diff = 0;
        TyReputationObject temp = oldReputationObject;
        // Original version had:
        //
        //    oldReputationObject[] = reputationObject[]
        //
        // This version is an attempt to save effort
        // by just switching round the memory the two
        // arrays are pointing at -- not sure if it
        // actually does what I'm expecting it to.
        // Doesn't seem to improve speed. :-(
        oldReputationObject = reputationObject;
        reputationObject = temp;
        reputationObject[] = 0;
        weightSum[] = 0;
        foreach (ref const(Rating) r; ratings) {
            reputationObject[r.object] += reputationUser[r.user] * r.value;
            weightSum[r.object] += reputationUser[r.user];
        }
        foreach (uint object, ref double r; reputationObject) {
            r /= (weightSum[object] > 0) ? weightSum[object] : 1;
            auto aux = (r - oldReputationObject[object]);
            diff += aux * aux;
        }
        return sqrt(diff);
    }
    void userReputationUpdate(ref TyRatings ratings,
                              TyReputationUser reputationUser,
                              TyReputationObject reputationObject) {
        reputationUser[] = 0;
        foreach (ref const(Rating) r; ratings) {
            auto aux = (r.value - reputationObject[r.object]);
            reputationUser[r.user] += aux * aux;
        }
        foreach (uint user, ref double r; reputationUser) {
            //if(userLinks[user]>0)
                r = pow( (r/reputationObject.length/*userLinks[user]*/) +
errorMin, -beta);
        }
    }
    void opCall(ref TyRatings ratings,
                ref TyReputationUser reputationUser,
                ref TyReputationObject reputationObject) {
    //    userLinks.length = reputationUser.length;
    //    userLinks[] = 0;
        weightSum.length = reputationObject.length;
        oldReputationObject.length = reputationObject.length;
    //    foreach (Rating r; ratings)
    //        userLinks[r.user]++;
        double diff;
        uint iterations = 0;
        do {
            userReputationUpdate(ratings, reputationUser, reputationObject);
            diff = objectReputationUpdate(ratings, reputationUser,
reputationObject);
            ++iterations;
        } while (diff > convergenceRequirement);
        printf("Exited in %u iterations with diff = %g < %g\n",
               iterations, diff, convergenceRequirement);
    }
    this() {}
    this(double b, double c, double e) {
        beta = b;
        convergenceRequirement = c;
        errorMin = e;
        assert(beta >= 0);
        assert(convergenceRequirement > 0);
        assert(errorMin >= 0);
    }
    this(ref TyRatings ratings,
         TyReputationUser reputationUser,
         ref TyReputationObject reputationObject,
         double b, double c, double e) {
        this(b, c, e);
        opCall(ratings, reputationUser, reputationObject);
    }
}
class AvgWeighted : ReputationAlgorithm {
    double[] weightSum;
    void opCall(ref TyRatings ratings,
                ref TyReputationUser reputationUser,
                ref TyReputationObject reputationObject) {
        weightSum.length = reputationObject.length;
        weightSum[] = 0;
        reputationObject[] = 0;
        foreach (ref const(Rating) r; ratings) {
            reputationObject[r.object] += reputationUser[r.user] * r.value;
            weightSum[r.object] += reputationUser[r.user];
        }
        foreach (uint o, ref double r; reputationObject)
            r /= weightSum[o];
    }
    this() {}
    this(ref TyRatings ratings,
         TyReputationUser reputationUser,
         TyReputationObject reputationObject) {
        opCall(ratings, reputationUser, reputationObject);
    }
}
final class AvgArithmetic : AvgWeighted {
    override void opCall(ref TyRatings ratings,
                         ref TyReputationUser reputationUser,
                         ref TyReputationObject reputationObject) {
        reputationUser[] = 1;
        super.opCall(ratings, reputationUser, reputationObject);
    }
    this() {}
    this(ref TyRatings ratings,
         ref TyReputationUser reputationUser,
         ref TyReputationObject reputationObject) {
        opCall(ratings, reputationUser, reputationObject);
    }
}
void main() {
    TyRatings ratings;
    TyReputationObject reputationObject;
    TyReputationUser reputationUser;
    double[] objectQuality, userError;
    scope auto aa = new AvgArithmetic;
    scope auto yzlm = new Yzlm(0.8, 1e-12, 1e-36);
    reputationObject.length = 1_000;
    reputationUser.length = 1_000;
    objectQuality.length = reputationObject.length;
    userError.length = reputationUser.length;
    ratings.length = reputationObject.length * reputationUser.length;
    FastRandom rnd;
    rnd.seed(1001);
    for (uint i; i < 10; i++) { // 100  4  ***************
        foreach (ref double Q; objectQuality)
            Q = rnd.uniform(0.0, 10.0);
        foreach (ref double sigma2; userError)
            sigma2 = rnd.random();
        int pos;
        foreach (uint object, ref double Q; objectQuality)
            foreach (uint user, ref double sigma2; userError)
                ratings[pos++] = Rating(user, object, rnd.uniform(Q - sigma2, Q
+ sigma2));
        printf("We now have %u ratings.\n", ratings.length);
        aa(ratings, reputationUser, reputationObject);
        yzlm(ratings, reputationUser, reputationObject);
        double deltaQ = 0;
        foreach (uint object, double r; reputationObject) {
            auto aux = (r - objectQuality[object]);
            deltaQ += aux * aux;
        }
        deltaQ = sqrt(deltaQ / reputationObject.length);
        printf("[%u] Error in quality estimate: %g\n", i, deltaQ);
    }
}
That's surely not perfect D code. Near its top you can see:
typedef double[] TyReputationUser;
typedef double[] TyReputationObject;
They allow me to tell apart the two arrays of doubles. This allows me to:
- give such arrays with a little more safety to methods and free functions. The
type systems catches errors if I swap them by mistake.
- If I want to change the representation of ReputationUser or ReputationObject,
like to an array of floats or an array or structs, etc, I have just to replace
that typedef line (this is true with an alias too).
If a typedef gets removed from D2 I can replace its functionality with a struct
with an alias this inside, but I have found the mapping array=>struct with
array inside and alias this is not transparent, it causes troubles that I'd
like to avoid.
Currently typedef can be used with classes too:
class Foo {}
typedef Foo Bar;
typedef int int2;
void main() {
    Foo f1 = new Foo;
    Bar b1 = new Bar;
    f1 = b1;
    b1 = f1; // Error: cannot implicitly convert expression (f1) of type
test.Foo to Bar
    int i1 = 1;
    int2 i2 = 2;
    i1 = i2;
    i2 = i1; // Error: cannot implicitly convert expression (i1) of type int to
int2
}
But I think mixing typedef and OOP is not tidy, so typedef can be forbidden on
classes.
Bye,
bearophile
 Apr 21 2010
Am 22.04.2010, 02:17 Uhr, schrieb bearophile <bearophileHUGS lycos.com>:In that thread people have said they find typedef useless, but I keep finding it useful even in partially OOP code too.Yeah me too. I use them in dsfml to ensure that pointers to structs passed to C functions are indeed correct and not some other pointers. And I think it has some use in LuaD as well representing the Lua 'nil' value.
 Apr 22 2010








 
  
  
  Trass3r <un known.com>
 Trass3r <un known.com>