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