www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Template error on compiling ...

reply "Robin" <robbepop web.de> writes:
Hiho,

I am currently working on a matrix library (matrices are 
templated structs) and have just implemented so-called 
"ElementalOperations" which perform certain tasks on mutable 
matrices.

There is an abstract ElementalOperation where three different 
ElementalOperation types inherit from. These ElementalOperations 
are structured like that:

module neoLab.core.ScaleRowOperation;

import neoLab.core.ElementalOperation;
import neoLab.core.Matrix;

final class ScaleRowOperation(T = double) : ElementalOperation
	if (!hasIndirections!T)
{
	private
	{
		size_t row = 0;
		T factor = 1;
	}

	this(size_t row, T factor) pure nothrow {
		this.row = row;
		this.factor = factor;
	}

	override void opCall(ref Matrix m) pure nothrow {
		foreach (immutable col; 0 .. m.getDimension().cols) {
			m[this.row, col] *= this.factor;
		}
	}

	override string toString() const pure nothrow {
		return "Scale all elements of row " ~ this.row ~
				" by factor " ~ this.factor ~ ".";
	}
}

So it is a fairly simple concept until now and I haven't spend 
time on improving its performance as I run into a strange 
compiler error, telling me the following:

neoLab/core/ElementalOperation.d(6): Error: struct 
neoLab.core.Matrix.Matrix(T = double) if (!hasIndirections!T) is 
used as a type
neoLab/core/SwapRowsOperation.d(18): Error: struct 
neoLab.core.Matrix.Matrix(T = double) if (!hasIndirections!T) is 
used as a type

The matrix struct is defined as follows:

struct Matrix(T = double) if (!hasIndirections!T)

In the documentation hasIndirections!T reads:
Returns true if and only if T's representation includes at least 
one of the following:
     - a  raw pointer U*;
     - an array U[];
     - a  reference to a class type C.
     - an associative array.
     - a  delegate.

I don't know why this error occures at all. In my opinion it 
shouldn't, or am I doing something wrong again?

Thanks in advance for help. =)

Robin
Feb 28 2014
parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Friday, 28 February 2014 at 19:09:11 UTC, Robin wrote:
 	override void opCall(ref Matrix m) pure nothrow {
 		foreach (immutable col; 0 .. m.getDimension().cols) {
 			m[this.row, col] *= this.factor;
 		}
I guess this is the culprit. You must use Matrix!(). In general if the compiler says that "X is used as type", where X is something like a template, than you are using the template X instead of an instance where you should not. There is probably an enhancement request to make the code above legal, though.
Feb 28 2014
parent reply "anonymous" <anonymous example.com> writes:
On Friday, 28 February 2014 at 19:16:11 UTC, Tobias Pankrath
wrote:
 On Friday, 28 February 2014 at 19:09:11 UTC, Robin wrote:
 	override void opCall(ref Matrix m) pure nothrow {
 		foreach (immutable col; 0 .. m.getDimension().cols) {
 			m[this.row, col] *= this.factor;
 		}
I guess this is the culprit. You must use Matrix!(). In general if the compiler says that "X is used as type", where X is something like a template, than you are using the template X instead of an instance where you should not. There is probably an enhancement request to make the code above legal, though.
Here it should probably be Matrix!T, though.
Feb 28 2014
parent reply "Robin" <robbepop web.de> writes:
Hiho,

both

opCall(ref Matrix!() m)

opCall(ref Matrix!T m)

aswell as

opCall(ref Matrix!(m))

or just

opCall(ref Matrix m)

give me all the same error as the one stated in the first post 
... :/

Nothing really seems to work here.

Robin
Feb 28 2014
parent reply "anonymous" <anonymous example.com> writes:
On Friday, 28 February 2014 at 19:33:17 UTC, Robin wrote:
 opCall(ref Matrix!() m)

 opCall(ref Matrix!T m)

 aswell as

 opCall(ref Matrix!(m))
This one's just nonsense.
 or just

 opCall(ref Matrix m)
This one gives you the "used as a type" kind of error message.
 give me all the same error as the one stated in the first post 
 ... :/
You're probably looking in the wrong place (for that particular error message). neoLab/core/ElementalOperation.d, line 6, and neoLab/core/SwapRowsOperation.d, line 18, are the spots the compiler complains about (so far).
 module neoLab.core.ScaleRowOperation;
suggests that you're looking at neither of those two files. You still have to fix it there, too, though.
Feb 28 2014
next sibling parent reply "Robin" <robbepop web.de> writes:
Hiho,

with

import neoLab.core.Matrix;

abstract class ElementalOperation(T = double) {
     abstract void opCall(ref Matrix!T m);
     abstract override string toString();
}

where I have made the abstract class templated "(T = double)" and 
where I have added a "!T" after "Matrix" in the opCall parameter 
list I get the following error:

/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crt1.o: 
In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
--- errorlevel 1

When I leave the (T = double) template assignment out I get 
another error:

neoLab/core/ElementalOperation.d(6): Error: undefined identifier T

With Tobias Pankrath's Matrix!() I get the following linker error:

/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crt1.o: 
In function `_start':
(.text+0x20): undefined reference to `main'
ScaleRowOperation.o: In function

.... many many many lines of unuseful error messages ...

(.text._D6neoLab4core6Matrix11__T6MatrixZ6Matrix6randomFxmxmdddZS6neoLab4core6Matrix11__T6Ma
rixZ6Matrix+0x145): 
undefined reference to 
`_D6neoLab4core9Dimension9Dimension4sizeMxFNaNbNdZm'
collect2: error: ld returned 1 exit status
--- errorlevel 1

So, in conclusion. I still have no clue why this more or less 
simple construct does not work but gives me errors on compiling.

Robin
Feb 28 2014
parent "anonymous" <anonymous example.com> writes:
On Friday, 28 February 2014 at 20:54:42 UTC, Robin wrote:
 Hiho,

 with

 import neoLab.core.Matrix;

 abstract class ElementalOperation(T = double) {
     abstract void opCall(ref Matrix!T m);
     abstract override string toString();
 }

 where I have made the abstract class templated "(T = double)" 
 and where I have added a "!T" after "Matrix" in the opCall 
 parameter list I get the following error:

 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crt1.o: 
 In function `_start':
 (.text+0x20): undefined reference to `main'
 collect2: error: ld returned 1 exit status
 --- errorlevel 1
The error message is unrelated. "undefined reference to `main'" -> no main function. You can add -main to your dmd invocation to let the compiler generate a dummy main.
 When I leave the (T = double) template assignment out I get 
 another error:

 neoLab/core/ElementalOperation.d(6): Error: undefined 
 identifier T
Well, sure, you just removed T.
 With Tobias Pankrath's Matrix!() I get the following linker 
 error:

 /usr/lib/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../lib/crt1.o: 
 In function `_start':
 (.text+0x20): undefined reference to `main'
Same as above: no main function.
 ScaleRowOperation.o: In function

 .... many many many lines of unuseful error messages ...

 (.text._D6neoLab4core6Matrix11__T6MatrixZ6Matrix6randomFxmxmdddZS6neoLab4core6Matrix11__T6Ma
rixZ6Matrix+0x145): 
 undefined reference to 
 `_D6neoLab4core9Dimension9Dimension4sizeMxFNaNbNdZm'
 collect2: error: ld returned 1 exit status
 --- errorlevel 1
Can't say much about this. Might just be fallout from previous failures.
 So, in conclusion. I still have no clue why this more or less 
 simple construct does not work but gives me errors on compiling.
Matrix!T is the way to go.
Feb 28 2014
prev sibling parent reply "Robin" <robbepop web.de> writes:
Hiho,

aww, that's a noob mistake of me.

Thanks!

Should take a closer look at the error messages next time a 
should think more about their special meaning ...

It works now while it feels strange that I have to template the 
three classes as I am only working with references to matrix and 
in my understanding this shouldn't affect the compilate. But, 
well, in the end it works now.^^

Robin
Feb 28 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 02/28/2014 02:21 PM, Robin wrote:

 I am only working with references to matrix and in my understanding this
 shouldn't affect the compilate.
As I understand it, Matrix is not a type; rather a type template. Only instances of that template like Matrix!double can be used as types. I was interested in this thread but I could not put pieces together in my mind without complete code. Could you please demonstrate the problem with minimal code next time. Thanks. :) Ali
Feb 28 2014
parent reply "Robin" <robbepop web.de> writes:
Hiho,

just for you: the whole code! =)
http://dpaste.dzfl.pl/cd1537571a4d

The idea is that I have matrix instances and so-called 
ElementalOperations which are able to operate on matrices to 
solve certain algorithms object oriented without nasty loops and 
so on.

This had worked perfectly in my java implementation so far.

Robin
Feb 28 2014
parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Friday, 28 February 2014 at 23:16:48 UTC, Robin wrote:
 Hiho,

 just for you: the whole code! =)
 http://dpaste.dzfl.pl/cd1537571a4d

 The idea is that I have matrix instances and so-called 
 ElementalOperations which are able to operate on matrices to 
 solve certain algorithms object oriented without nasty loops 
 and so on.
I'm going to repeat the advice from your thread about matrices: don't use upper case in module names. See http://dlang.org/module.html#ModuleDeclaration. "delete" keyword will eventually go away, you're better off not using it. Now to a suggestion: how about going up a type so you don't have to carry around the (T = double) and Matrix!T code dependencies? The tests below are simplified and clumped together, but should be enough for an illustration. struct Matrix(T = double) { /* blah */ } /// Tests if type M is a Matrix enum bool isSomeMatrix(M) = is(M == Matrix!T, T); /// Gets element type from a Matrix type alias MatrixElement(M : Matrix!T, T) = T; abstract class ElementalOperation(M) if (isSomeMatrix!M) { /* blah */ } unittest { import std.typetuple; alias types = TypeTuple!(byte,short,int,long,float,double); foreach(T; types) { // don't accept scalars static assert(!isSomeMatrix!T); static assert(!is(MatrixElement!T)); static assert(!is(ElementalOperation!T)); // accept matrices static assert(isSomeMatrix!(Matrix!T)); static assert(is(MatrixElement!(Matrix!T) == T)); static assert(is(ElementalOperation!(Matrix!T))); } } This way all ElementalOperation's method signatures will transform from void foo(Matrix!T m) into void foo(M m), and the MatrixElement template will help in cases when you do need to get to underlying type.
 This had worked perfectly in my java implementation so far.
Well, D is not Java ;) As Ali mentioned, Matrix is not a type, Matrix!T is.
Feb 28 2014
parent reply "Meta" <jared771 gmail.com> writes:
EOn Saturday, 1 March 2014 at 00:17:55 UTC, Stanislav Blinov 
wrote:
 /// Tests if type M is a Matrix
 enum bool isSomeMatrix(M) = is(M == Matrix!T, T);
Unrelated, but it may be of some interest. This isn't really a good way to define your isSomeMatrix template, i.e., tying it to a specific type. What if you want to extend your matrix library in the future to include ScalarMatrix, UpperTriangularMatrix, etc. implementations? While these are matrices, they will fail isSomeMatrix as it is defined. A better way when using templates is to define a number of primitives required for an object to be a matrix, and then test for those primitives in isSomeMatrix to determine if M is a matrix. This is the concept of duck-typing, and its how D's ranges are defined. This way, anything that implements the range protocol can be operated on by any range algorithm. It's quite flexible and powerful.
Feb 28 2014
parent "Robin" <robbepop web.de> writes:
Hiho,

thank you for your responses.
This D language meta programming sounds funny and strange to
someone who has never really worked with something like this but
I understand its importance and will look more into working with
it. =)

Robin
Mar 01 2014