www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - type promotion (on overloaded operators)

reply wondermail szm.sk writes:
Hi there,
I've just read the spec - great D, but can I somehow do the "type promotion"
e.g. for matrices

class CMatrix(T, int M, int N)
{
T data[M][N];
}

CMatrix!(float,3,3) mf;
CMatrix!(double,3,3) md;

mf + md; // float matrix + double matrix = double matrix

// or

CMatrix!(float,1,3) v3;
CMatrix!(float,3,3) m33;

v3 * m33; // and this is really necessary to me


-----------
In C++ I did something like this:

template <class X, class Y> TAdd {};

template <> TAdd<float,double> { typedef double RET; }; // float + double =
double

template <class X, class Y, int M, int N> CMatrix<typename TAdd<X,Y>::RET,M,N>
operator + (CMatrix<T,M,N> const &a, CMatrix<T,M,N> const &b) { /*...*/ }

thanks Juraj Onderik
(as I understand templates in D now - it's not really superset of C++ templates,
or is it? :)

Juraj Onderik
Oct 10 2004
next sibling parent reply Sjoerd van Leent <svanleent wanadoo.nl> writes:
wondermail szm.sk wrote:
 Hi there,
 I've just read the spec - great D, but can I somehow do the "type promotion"
 e.g. for matrices
 
 class CMatrix(T, int M, int N)
 {
 T data[M][N];
 }
 
 CMatrix!(float,3,3) mf;
 CMatrix!(double,3,3) md;
 
 mf + md; // float matrix + double matrix = double matrix
 
 // or
 
 CMatrix!(float,1,3) v3;
 CMatrix!(float,3,3) m33;
 
 v3 * m33; // and this is really necessary to me
 
 
 Juraj Onderik

use a bare template to perform bold action. Example: class Matrix(T, int M, int N) { T data[M][N]; } // bare template template MatrixWorker(Ta, Tb, int Dx, int Dy, To) { Matrix!(To, Dx, Dy) dotProduct( in Matrix!(Ta, Dx, Dy) first, in Matrix!(Tb, Dx, Dy) second) { Matrix!(To, Dx, Dy) result = new Matrix!(To, Dx, Dy); for(uint i; i < Dx; i++) { for(uint j; j < Dy; j++) { result.data[i][j] = cast(To)first.data[i][j] * cast(To)second.data[i][j]; } } return result; } Matrix!(To, Dx, Dy) sum( in Matrix!(Ta, Dx, Dy) first, in Matrix!(Tb, Dx, Dy) second) { Matrix!(To, Dx, Dy) result = new Matrix!(To, Dx, Dy); for(uint i; i < Dx; i++) { for(uint j; j < Dy; j++) { result.data[i][j] = cast(To)first.data[i][j] + cast(To)second.data[i][j]; } } return result; } } int main(char[][] args) { Matrix!(float,3,3) mf = new Matrix!(float,3,3)(/*Matrix init!*/); Matrix!(double,3,3) md = new Matrix!(double,3,3)(/*Matrix init!*/); Matrix!(double,3,3) mo; mo = MatrixWorker!(float, double, 3, 3, double).dotProduct(mf, md); // or mo = MatrixWorker!(float, double, 3, 3, double).sum(mf, md); return 0; } I think this should help. Of course, you can now write specific operators to perform it less painful ;-) But this should give you a kickstart. Regards, Sjoerd N.B. This is D, not MFC, so leave out the C prefix, it's unwanted by the community and especially the big boss.
Oct 10 2004
parent reply Juraj Onderik <Juraj_member pathlink.com> writes:
sure I know this :) Ok I meant it little bit different. Can I do "template
function" :

C++ :
template <class X, class Y> void foo(X x, Y y) {} // general code
// specializations - ...

foo(1.2,3);
foo("one", "two");
//

D:
template Foo(X,Y)
{
void foo(X x, Y y) {}
}

// a,b - some objects , you have specialized Foo for them

Foo!(typeof(a),typeof(b)).foo(a,b); // OK
foo(a,b); // bad - you must provide "template scope"

So the "problem" is that compiler can't deduce template parameters from the
function parameters - what c++ actually does. Sure it's not wrong, cause
templates in D are new scopes.
Anyway, sorry, but I still can't see, how to do it with operators, bacause I
cannot parametrize it's argument's:

template TM(X, int M, int N)
{
class Matrix
{
template NewScope(Y) { void opAdd(TM!(Y,M,N).Matrix m) { /*..*/ } }
void opAdd(Matrix m) { /*...*/ } // m is TM!(T,M,N).Matrix
}
}

void main ()
{
TM!(float,3,3).Matrix a;
TM!(double,3,3).Matrix b;

a.opAdd(b); // this (float,3,3) + (float,3,3)
a.NewScope!(double).opAdd(b); // this is NOT + operator

}


use a bare template to perform bold action. Example:
     mo = MatrixWorker!(float, double, 3, 3, double).dotProduct(mf, md);

dot(a,b) = scalar - not a matrix :) Ok just for fun.
I think this should help. Of course, you can now write specific 
operators to perform it less painful ;-) But this should give you a 
kickstart.

N.B. This is D, not MFC, so leave out the C prefix, it's unwanted by the 
community and especially the big boss.

well I dont use MFC at all, but the C prefix means: class CFoo {} struct SFoo {} enum EFoo {} union UFoo {} but if the BIG boss is against I dont mind :)
Oct 10 2004
parent Ben Hinkle <bhinkle4 juno.com> writes:
The following should help illustrate my earlier post. It probably
wouldn't be hard to share more code than I do below but you get the
idea.

import std.stdio;
template GenericVectorOps(Vector,T,int N) {
  // arithmetic with the same underlying data types
  Vector opAdd(Vector y) {
    Vector res;
    for(int k=0;k<N;k++) {
      res.data[k] = data[k]+y.data[k];
    }
    return res;
  }
  // print out a Vector
  void print() {
    foreach(T val; data) writef(val," ");
    writefln();
  }
}
struct Vector(T,int N) {
  T[N] data;
  mixin GenericVectorOps!(Vector,T,N) gops;
  alias gops.opAdd opAdd;
}
struct Vector(T:double,int N) {
  T[N] data;
  mixin GenericVectorOps!(Vector,T,N) gops;
  alias gops.opAdd opAdd;
  // now define mixed type arithmetic with double and float
  Vector opAdd(.Vector!(float,N) y) {
    Vector res;
    for(int k=0;k<N;k++) {
      res.data[k] = data[k]+y.data[k];
    }
    return res;
  }
}
int main() {
  Vector!(double,3) x;
  x.data[0] = 1;
  x.data[1] = 2;
  x.data[2] = 3;
  Vector!(float,3) y;
  y.data[0] = 10;
  y.data[1] = 20;
  y.data[2] = 30;
  Vector!(double,3) z = x+y;
  Vector!(double,3) w = z+x;
  x.print();
  y.print();
  z.print();
  w.print();
  return 0;
}
Oct 10 2004
prev sibling parent Ben Hinkle <bhinkle4 juno.com> writes:
wondermail szm.sk wrote:

 Hi there,
 I've just read the spec - great D, but can I somehow do the "type
 promotion" e.g. for matrices
 
 class CMatrix(T, int M, int N)
 {
 T data[M][N];
 }
 
 CMatrix!(float,3,3) mf;
 CMatrix!(double,3,3) md;
 
 mf + md; // float matrix + double matrix = double matrix
 
 // or
 
 CMatrix!(float,1,3) v3;
 CMatrix!(float,3,3) m33;
 
 v3 * m33; // and this is really necessary to me
 

You could try something like template GenericMatrixOps(Matrix,int M, int N) { Matrix opAdd(Matrix y) { // define addition Matrix+Matrix } } class Matrix(T:double, int M, int N) { T[M][N] data; mixin GenericMatrixOps!(Matrix,M,N) genericOps; alias genericOps.opAdd opAdd; // for overloading, maybe Matrix opAdd(Matrix!(float,M,N) y) { // define what to do with double+float matrices } } I haven't actually tried writing something out and compiling it but the general idea is to use mixins to share code and template specialization to define the special cases for mixed type arithmetic.
 -----------
 In C++ I did something like this:
 
 template <class X, class Y> TAdd {};
 
 template <> TAdd<float,double> { typedef double RET; }; // float + double
 = double
 
 template <class X, class Y, int M, int N> CMatrix<typename
 TAdd<X,Y>::RET,M,N> operator + (CMatrix<T,M,N> const &a, CMatrix<T,M,N>
 const &b) { /*...*/ }
 
 thanks Juraj Onderik
 (as I understand templates in D now - it's not really superset of C++
 templates, or is it? :)
 
 Juraj Onderik

D doesn't have implicit template instantiation so using "pure templates" will probably end up being more verbose than in C++. If you use member functions then you don't have to worry about instantiating the templates. -Ben
Oct 10 2004