www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Chain two different struct specialization

reply "Andrea Fontana" <nospam example.com> writes:
I'm trying to do something like this. I don't know whether or not 
it's a good idea, i'm open to solutions and suggestions

struct MyStruct(WEIGHTS)
{
    string ...
    string ...

    alias WEIGHTS weights;
}

double likeness(T,T1)(ref in T1, ref in T2)
{
     // Here i do some complex calculus using struct fields
     // and using weights consts
}

enum FirstWeights : double
{

}
Mar 01 2013
parent reply "Andrea Fontana" <nospam example.com> writes:
On Friday, 1 March 2013 at 14:27:40 UTC, Andrea Fontana wrote:
 I'm trying to do something like this. I don't know whether or 
 not it's a good idea, i'm open to solutions and suggestions

 struct MyStruct(WEIGHTS)
 {
    string ...
    string ...

    alias WEIGHTS weights;
 }

 double likeness(T,T1)(ref in T1, ref in T2)
 {
     // Here i do some complex calculus using struct fields
     // and using weights consts
 }

 enum FirstWeights : double
 {

 }
Ops. Here the complete message: I'm trying to do something like this. I don't know whether or not it's a good idea, i'm open to solutions and suggestions struct MyStruct(WEIGHTS) { string ... string ... alias WEIGHTS weights; } double likeness(T,T1)(ref in T1, ref in T2) { // Here i do some complex calculus using struct fields // and using weights consts } enum FirstWeights : double { double foo = 0.3, double bar = 0.4 } enum SecondWeights : double { double foo = 0.3, double bar = 0.4 } so: auto s1 = MyStruct!FirstWeights ... auto s2 = MyStruct!SecondWeights ... likeness(s1,s2); // works But I can't mix different type (s1,s2) on a single range or array, to check for likeness, is there a way? (or should I avoid template init a double[] weights field)
Mar 01 2013
next sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Andrea Fontana:

 double likeness(T,T1)(ref in T1, ref in T2)
==> double likeness(T1, T2)(in ref T1, in ref T2) Bye, bearophile
Mar 01 2013
parent reply "Andrea Fontana" <nospam example.com> writes:
On Friday, 1 March 2013 at 14:39:53 UTC, bearophile wrote:
 Andrea Fontana:

 double likeness(T,T1)(ref in T1, ref in T2)
==> double likeness(T1, T2)(in ref T1, in ref T2) Bye, bearophile
Sure not the only error. I was writing "pseudo code". Real code it's quite complex. Try this one (is a really reduced working example): struct MyStruct(WEIGHTS) { this (int p, int p2) { prop = p; prop2 = p2; } int prop; int prop2; alias WEIGHTS weights; } double likeness(T1,T2)(ref in T1 first, ref in T2 second) { double v = (first.prop - second.prop) * first.weights.foo * second.weights.foo; v += (first.prop2 - second.prop2) * first.weights.bar * second.weights.bar; return v; } enum FirstWeights : double { foo = 0.3, bar = 0.4 } enum SecondWeights : double { foo = 0.5, bar = 0.2 } void main(string[] args) { auto s1 = MyStruct!FirstWeights(10,8); auto s2 = MyStruct!FirstWeights(9, 10); auto s3 = MyStruct!SecondWeights(9,10); writeln(likeness(s1,s2)); // works writeln(likeness(s1,s3)); // works } How to put s1,s2,3... in a range/array or something similar/iterable? Probably there's no way (inside variant?)...
Mar 01 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Andrea Fontana:

 How to put s1,s2,3... in a range/array or something 
 similar/iterable? Probably there's no way (inside variant?)...
One solution is to not use templates: immutable struct Weights { double foo, bar; } enum Weights firstWeights = { foo: 0.3, bar: 0.4 }, secondWeights = { foo: 0.5, bar: 0.2 }; struct MyStruct { int prop, prop2; immutable Weights weights; this ( Weights weights_, in int p, in int p2) pure nothrow { prop = p; prop2 = p2; } } double likeness(in ref MyStruct first, in ref MyStruct second) { double v = (first.prop - second.prop) * first.weights.foo * second.weights.foo; return v + (first.prop2 - second.prop2) * first.weights.bar * second.weights.bar; } void main() { immutable s1 = MyStruct(firstWeights, 10, 8); immutable s2 = MyStruct(firstWeights, 9, 10); immutable s3 = MyStruct(secondWeights, 9, 10); import std.stdio; writeln(likeness(s1, s2)); writeln(likeness(s1, s3)); const r = [s1, s2, s3]; } Bye, bearophile
Mar 01 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
 void main() {
 	immutable s1 = MyStruct(firstWeights,  10,  8);
 	immutable s2 = MyStruct(firstWeights,   9, 10);
 	immutable s3 = MyStruct(secondWeights,  9, 10);

      import std.stdio;
 	writeln(likeness(s1, s2));
Sorry for the mix of tabs and spaces. The crappy editor I have used now has not replaced your tabs with spaces... Bye, bearophile
Mar 01 2013
parent reply "Andrea Fontana" <nospam example.com> writes:
On Friday, 1 March 2013 at 15:08:21 UTC, bearophile wrote:
 void main() {
 	immutable s1 = MyStruct(firstWeights,  10,  8);
 	immutable s2 = MyStruct(firstWeights,   9, 10);
 	immutable s3 = MyStruct(secondWeights,  9, 10);

     import std.stdio;
 	writeln(likeness(s1, s2));
Sorry for the mix of tabs and spaces. The crappy editor I have used now has not replaced your tabs with spaces... Bye, bearophile
That's right. I think you missed an initialization on this(): I fixed it. BTW, compiler can't guess s1 and s2 weights, should it? if inside likeness() i write: enum test = first.weights.foo * second.weights.foo; it said that can't read first and second value at compile time. Andrea
Mar 01 2013
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Andrea Fontana:

 BTW, compiler can't guess s1 and s2 weights, should it?

 if inside likeness() i write:

 enum test = first.weights.foo * second.weights.foo;

 it said that can't read first and second value at compile time.
firstWeights and secondWeights are compile-time constants, but the arguments you give to likeness are run-time values, so they are unknown at compile-time inside likeness. There are ways to solve that problem, but I don't know how much good this is: immutable struct Weights { double foo, bar; } enum Weights firstWeights = { foo: 0.3, bar: 0.4 }, secondWeights = { foo: 0.5, bar: 0.2 }; struct MyStruct { int prop, prop2; immutable Weights weights; this(Weights weights_, in int p, in int p2) pure nothrow { this.weights = weights_; this.prop = p; this.prop2 = p2; } } double likeness(alias first, alias second)() { enum test = first.weights.foo * second.weights.foo; double v = (first.prop - second.prop) * first.weights.foo * second.weights.foo; return v + (first.prop2 - second.prop2) * first.weights.bar * second.weights.bar; } void main() { enum s1 = MyStruct(firstWeights, 10, 8); enum s2 = MyStruct(firstWeights, 9, 10); enum s3 = MyStruct(secondWeights, 9, 10); import std.stdio; writeln(likeness!(s1, s2)()); writeln(likeness!(s1, s3)()); const r = [s1, s2, s3]; } Bye, bearophile
Mar 01 2013
parent reply "Andrea Fontana" <nospam example.com> writes:
On Friday, 1 March 2013 at 16:03:58 UTC, bearophile wrote:
 Andrea Fontana:

 BTW, compiler can't guess s1 and s2 weights, should it?

 if inside likeness() i write:

 enum test = first.weights.foo * second.weights.foo;

 it said that can't read first and second value at compile time.
firstWeights and secondWeights are compile-time constants, but the arguments you give to likeness are run-time values, so they are unknown at compile-time inside likeness. There are ways to solve that problem, but I don't know how much good this is: immutable struct Weights { double foo, bar; } enum Weights firstWeights = { foo: 0.3, bar: 0.4 }, secondWeights = { foo: 0.5, bar: 0.2 }; struct MyStruct { int prop, prop2; immutable Weights weights; this(Weights weights_, in int p, in int p2) pure nothrow { this.weights = weights_; this.prop = p; this.prop2 = p2; } } double likeness(alias first, alias second)() { enum test = first.weights.foo * second.weights.foo; double v = (first.prop - second.prop) * first.weights.foo * second.weights.foo; return v + (first.prop2 - second.prop2) * first.weights.bar * second.weights.bar; } void main() { enum s1 = MyStruct(firstWeights, 10, 8); enum s2 = MyStruct(firstWeights, 9, 10); enum s3 = MyStruct(secondWeights, 9, 10); import std.stdio; writeln(likeness!(s1, s2)()); writeln(likeness!(s1, s3)()); const r = [s1, s2, s3]; } Bye, bearophile
but: enum s1 = MyStruct(firstWeights, 10, 8); enum s2 = MyStruct(firstWeights, 9, 10); writeln(likeness(s1, s2)); still gives error: and s1 and s2 are known at compile time, aren't them? Your solution will create code for each item couple, isn't it? Not good in my case :) Other ideas?
Mar 01 2013
parent "bearophile" <bearophileHUGS lycos.com> writes:
Andrea Fontana:

 but:

 enum s1 = MyStruct(firstWeights,  10,  8);
 enum s2 = MyStruct(firstWeights,   9, 10);

 writeln(likeness(s1, s2));

 still gives error: and s1 and s2 are known at compile time, 
 aren't them?
Right. But they are known at compile-time only outside likeness().
 Your solution will create code for each item couple, isn't it?
Right.
 Not good in my case :) Other ideas?
Another solution is to use indirection, with classes or unsafe casts. Or to use variants. No solution is perfect. Why do you want to perform those computations at compile-time? Bye, bearophile
Mar 01 2013
prev sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 1 March 2013 at 14:32:12 UTC, Andrea Fontana wrote:
 struct MyStruct(WEIGHTS)
 {
   string ...
   string ...

   alias WEIGHTS weights;
 }
 enum FirstWeights : double
 {

 }
enum SecondWeights : double { double foo = 0.3, double bar = 0.4 } so: auto s1 = MyStruct!FirstWeights ... auto s2 = MyStruct!SecondWeights ...
With templates there's a few different ways you can consider handling it; I'm not recommending any of them but. Keeping it simple, clean & easy to read is probably the best solution; Although most of these won't help with any algorithms that need them to be identical (unless cast or they are not templates). 1) If structs are the same size: You can forcibly cast it so one will work with the other, however enums (or anything related that's static or not stored with the struct) doesn't transfer over and is lost. I've tried this in my experimental polymorphic struct; Where the methods differed slightly but data the structure is guaranteed to be identical. 2) Conversion/Accessing differences: You can include a flag specifying it's of a certain type or qualification, this can let them interact if they are basically the same thing with something minor under the hood different but that doesn't matter (or will get in the way); Although unqual (or related in std.traits) might be a better option for it, not sure myself. struct MyStruct(WEIGHTS) { enum isMyStruct = true; } void test(T1, T2)(T1 lhs, T2 rhs) if (hasMember!(T1, "isMyStruct") && hasMember!(T2, "isMyStruct")) {} 3) non-Template: As mentioned you can avoid templates & different enums and instead use variables as appropriate. I'm sure there's other ideas but I'm drawing a blank right now...
Mar 01 2013
parent "Andrea Fontana" <nospam example.com> writes:
On Friday, 1 March 2013 at 16:38:39 UTC, Era Scarecrow wrote:
 On Friday, 1 March 2013 at 14:32:12 UTC, Andrea Fontana wrote:
 struct MyStruct(WEIGHTS)
 {
  string ...
  string ...

  alias WEIGHTS weights;
 }
 enum FirstWeights : double
 {

 }
enum SecondWeights : double { double foo = 0.3, double bar = 0.4 } so: auto s1 = MyStruct!FirstWeights ... auto s2 = MyStruct!SecondWeights ...
With templates there's a few different ways you can consider handling it; I'm not recommending any of them but. Keeping it simple, clean & easy to read is probably the best solution; Although most of these won't help with any algorithms that need them to be identical (unless cast or they are not templates). 1) If structs are the same size: You can forcibly cast it so one will work with the other, however enums (or anything related that's static or not stored with the struct) doesn't transfer over and is lost. I've tried this in my experimental polymorphic struct; Where the methods differed slightly but data the structure is guaranteed to be identical. 2) Conversion/Accessing differences: You can include a flag specifying it's of a certain type or qualification, this can let them interact if they are basically the same thing with something minor under the hood different but that doesn't matter (or will get in the way); Although unqual (or related in std.traits) might be a better option for it, not sure myself. struct MyStruct(WEIGHTS) { enum isMyStruct = true; } void test(T1, T2)(T1 lhs, T2 rhs) if (hasMember!(T1, "isMyStruct") && hasMember!(T2, "isMyStruct")) {} 3) non-Template: As mentioned you can avoid templates & different enums and instead use variables as appropriate. I'm sure there's other ideas but I'm drawing a blank right now...
Maybe if i have MyStruct!Weights1 arr[]; MyStruct!Weights2 arr2[]; instead of trying to merge them, and call: myfunc(singlebigarray); I should write a template function with a variadic number of params: myfunc(arr1, arr2, arr3 etc...); Or simply come back to basic ineritance or previous solution, was just a challenge to find a compile time way to pre-compute all consts factors...
Mar 01 2013