Timon is, of course, right. I got a bit confused when trying to simplify in a hurry. What I meant was actually something like this:

ops.d:
import std.stdio;

int sum( T )( T mat ){
writeln("ops.sum");
// return reduce!"a+b"( 0, mat );
return 1;
}

int numelems( T )( T mat ) {
// return mat.rows * mat.columns;
return 1;
}

int mean( T )( T mat ) {
return sum( mat ) / numelems( mat );
}

diagonal.d:
import ops;
import std.stdio;

struct DiagonalMatrix {
}

int sum( T : DiagonalMatrix )( T mat ) {
writeln( "diagonal.sum" );
// return reduce!"a+b"( 0, mat.diagonal() );
return 1;

main.d:
import ops;
import diagonal;

void main() {
DiagonalMatrix mat;
sum( mat );   // this will not compile, but if removed mean
mean( mat ); // will use ops.sum, not diagonal.sum anyway
}

The first problem could, in theory, be fixed using a member flag, something like enum specializedSum = true; and ops.sum could be redefined as: int sum( T )( T mat ) if( !T.specializedSum ) {}. But in this case mean() would still try to use  ops.sum which will fail. All of this can be easily fixed by providing member functions, and having the free functions call the member ones when they exist.

---
Cristi Cobzarenco
BSc in Artificial Intelligence and Computer Science
University of Edinburgh
Profile: http://www.google.com/profiles/cristi.cobzarenco



On 10 April 2012 10:35, Timon Gehr <timon.gehr@gmx.ch> wrote:
On 04/10/2012 03:24 AM, Cristi Cobzarenco wrote:
Thanks for the suggestions!

I don't think UFCS would help us. Our problem is that we can't do this:
triangular.d:
  struct TriangularMatrix {

  }

  void sum( T )( T x ) if( is( T : TriangularMatrix ) ) {

  }

diagonal.d:
  struct DiagonalMatrix {

  }

  void sum( T )( T x ) if( is( T : DiagonalMatrix ) ) {
  }

main.d:
import diagonal;
import triangular;

void bar() {
   TriangularMatrix a;
   Diagonal b;
   sum( a );  // this does not compile because sum() is ambiguous
   sum( b );  // nor does this
}

There are no ambiguities in that example, and if ambiguities occur, they can always be fixed manually.


This, AFAIK, is deliberate to avoid name hijacking - ADL in C++ had its
share of criticism. I doubt we will ever get this behaviour in D and
that is perhaps a good thing. I may have misunderstood UFCS though - or
what you meant by making non-member function calls look nicer - please
correct me if that's the case.

Don't worry about long names, t() is already the way transposition is
defined SciD. Moreover, it's a property so you can actually do "a.t * a"
- convenience galore. I'm also considering of creating a submodule like
std.linalg.short which defines aliases with short names for types and
free functions - this will allow particularly numerics-heavy functions
to be written more compactly. I'm not entirely sure it would be a good
idea though as it may sacrifice readability where it's most needed.

---
Cristi Cobzarenco
BSc in Artificial Intelligence and Computer Science
University of Edinburgh
Profile: http://www.google.com/profiles/cristi.cobzarenco


If you change 'Diagonal' to 'DiagonalMatrix', this compiles fine.