digitalmars.D.learn - opCast using in template struct
- Oleg (25/25) Oct 18 2012 Hello. How to cast template struct to itself?
- Simen Kjaeraas (25/50) Oct 18 2012 I don't see a cast there. Do you?
- Oleg (27/27) Oct 18 2012 Sorry. My problem more complex and my simplification is not
- Simen Kjaeraas (4/30) Oct 18 2012 I see you have opOpBinary there - should those be opOpAssign?
- Era Scarecrow (5/6) Oct 18 2012 Probably. It's an easy mistake to make. Maybe the compiler
- bearophile (6/9) Oct 18 2012 If you have strong feelings about this, then add a Bugzilla entry.
- Timon Gehr (7/15) Oct 18 2012 This would have to be implemented very carefully. There are enough
- Era Scarecrow (10/17) Oct 18 2012 Inside a function a badly named identifier becomes obvious since
- bearophile (6/9) Oct 18 2012 Regarding operator overloading there are several situations worth
- Timon Gehr (2/10) Oct 18 2012 What situations?
- bearophile (11/12) Oct 18 2012 This thread has already shown two possible cases worth discussing
- Timon Gehr (4/15) Oct 18 2012 That is not even going to pass the lexing stage.
- Timon Gehr (11/29) Oct 18 2012 My suggestion was something like:
- Era Scarecrow (16/20) Oct 18 2012 But not everything is parsed/compiled if it doesn't match the
- Oleg (33/33) Oct 19 2012 Problem solved partially.
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (19/45) Dec 08 2012 E[DLen] is good above. You can also consider taking by 'const ref' if
Hello. How to cast template struct to itself? struct vec(string S,T=double) { T[S.length] data; auto opCast(string K,E)() if( S.length == K.length && is( T : E ) ) { vec!(K,E) ret; foreach( i, ref m; ret.data ) m = data[i]; return ret; } } unittest { alias vec!"xyz" dvec3; alias vec!("rbg",float) fcol3; auto a = dvec3([1,2,3]); auto b = fcol3(); assert( b.data == [1,2,3] ); } of type vec!("xyz") to vec!("rbg",float)
Oct 18 2012
On 2012-10-18, 16:54, Oleg wrote:Hello. How to cast template struct to itself? struct vec(string S,T=double) { T[S.length] data; auto opCast(string K,E)() if( S.length == K.length && is( T : E ) ) { vec!(K,E) ret; foreach( i, ref m; ret.data ) m = data[i]; return ret; } } unittest { alias vec!"xyz" dvec3; alias vec!("rbg",float) fcol3; auto a = dvec3([1,2,3]); auto b = fcol3(); assert( b.data == [1,2,3] ); } of type vec!("xyz") to vec!("rbg",float)I don't see a cast there. Do you? What you want is to overload the assignment operator, opAssign: struct vec(string S,T=double) { T[S.length] data; void opAssign(string K,E)(vec!(K,E) value) if( S.length == K.length && is( E : T ) ) { foreach( i, ref m; value.data ) data[i] = m; } } unittest { alias vec!"xyz" dvec3; alias vec!("rbg",float) fcol3; auto a = dvec3([1,2,3]); auto b = fcol3(); assert( b.data == [1,2,3] ); } -- Simen
Oct 18 2012
Sorry. My problem more complex and my simplification is not correct. I want use mixin for math operations. mixin template vectOp( string DataName, int DataLen, T, vecType ) { mixin( "alias " ~ DataName ~ " this;" ); .... auto opBinary(string op,E)( E[DataLen] b ) .... auto opBinary(string op,E)( E[] b ) .... auto opOpBinary(string op,E)( E[] b ) .... auto opOpBinary(string op,E)( E[DataLen] b ) .... .... } struct vec(string S,T=double) { T[S.length] data; mixin vectOp( "data", S.length, T, vec!(S,T) ); } unittest{ vec!"xyz" a; vec!"xyz" b; a += b; } and it isn't work Error: 'a += b' is not a scalar, it is a vec!("xyz") Error: 'a._data' is not of arithmetic type, it is a double[3LU] Error: 'b._data' is not of arithmetic type, it is a double[3LU]
Oct 18 2012
On 2012-10-18, 17:45, Oleg wrote:Sorry. My problem more complex and my simplification is not correct. I want use mixin for math operations. mixin template vectOp( string DataName, int DataLen, T, vecType ) { mixin( "alias " ~ DataName ~ " this;" ); .... auto opBinary(string op,E)( E[DataLen] b ) .... auto opBinary(string op,E)( E[] b ) .... auto opOpBinary(string op,E)( E[] b ) .... auto opOpBinary(string op,E)( E[DataLen] b ) .... .... } struct vec(string S,T=double) { T[S.length] data; mixin vectOp( "data", S.length, T, vec!(S,T) ); } unittest{ vec!"xyz" a; vec!"xyz" b; a += b; } and it isn't work Error: 'a += b' is not a scalar, it is a vec!("xyz") Error: 'a._data' is not of arithmetic type, it is a double[3LU] Error: 'b._data' is not of arithmetic type, it is a double[3LU]I see you have opOpBinary there - should those be opOpAssign? -- Simen
Oct 18 2012
On Thursday, 18 October 2012 at 18:12:49 UTC, Simen Kjaeraas wrote:I see you have opOpBinary there - should those be opOpAssign?Probably. It's an easy mistake to make. Maybe the compiler should issue a warning when opAssign attempts and fails and opOpBinary is defined.
Oct 18 2012
Era Scarecrow:It's an easy mistake to make. Maybe the compiler should issue a warning when opAssign attempts and fails and opOpBinary is defined.If you have strong feelings about this, then add a Bugzilla entry. There are other cases. Generally the D compiler should add some warnings that help against operator overloading mistakes. Bye, bearophile
Oct 18 2012
On 10/18/2012 11:45 PM, bearophile wrote:Era Scarecrow:This would have to be implemented very carefully. There are enough hard to reproduce symbol resolution bugs already. It does not get better by introducing hidden and unnecessary lookups.It's an easy mistake to make. Maybe the compiler should issue a warning when opAssign attempts and fails and opOpBinary is defined.If you have strong feelings about this, then add a Bugzilla entry. There are other cases. Generally the D compiler should add some warnings that help against operator overloading mistakes. Bye, bearophileI don't think that operator overloading gives rise to distinct mistakes. For example, better error messages that just specify the expected name, as in other cases of undefined identifiers, would already fix this.
Oct 18 2012
On Thursday, 18 October 2012 at 22:07:55 UTC, Timon Gehr wrote:On 10/18/2012 11:45 PM, bearophile wrote:Inside a function a badly named identifier becomes obvious since it outright tells you. But with regards to opOpAssign and other operator overloading I see the error message and I see the call but I don't see why it fails. Then I'll try adjusting the signature on my function, not realizing it never sees it in the first place due to misspelling. Maybe.. A general warning when something starts with 'op(Op)?[A-Z]' but doesn't actually qualify as any of the override-able operators? That seems sensible...There are other cases. Generally the D compiler should add some warnings that help against operator overloading mistakes.I don't think that operator overloading gives rise to distinct mistakes. For example, better error messages that just specify the expected name, as in other cases of undefined identifiers, would already fix this.
Oct 18 2012
Era Scarecrow:Maybe.. A general warning when something starts with 'op(Op)?[A-Z]' but doesn't actually qualify as any of the override-able operators? That seems sensible...Regarding operator overloading there are several situations worth warning the programmer of. The D compilers should be improved on this. Bye, bearophile
Oct 18 2012
On 10/19/2012 01:23 AM, bearophile wrote:Era Scarecrow:What situations?Maybe.. A general warning when something starts with 'op(Op)?[A-Z]' but doesn't actually qualify as any of the override-able operators? That seems sensible...Regarding operator overloading there are several situations worth warning the programmer of. The D compilers should be improved on this. Bye, bearophile
Oct 18 2012
Timon Gehr:What situations?This thread has already shown two possible cases worth discussing about. This report shows two more cases: http://d.puremagic.com/issues/show_bug.cgi?id=8844 Two more cases: Foo opBinary(string op="/\")(Foo f) {} Foo opBinary(string op)(Foo f) if (op == " ") {} And several other situations. Bye, bearophile
Oct 18 2012
On 10/19/2012 02:12 AM, bearophile wrote:Timon Gehr:How is that bug-prone? Are there keyboards where : and = are close?What situations?This thread has already shown two possible cases worth discussing about. This report shows two more cases: http://d.puremagic.com/issues/show_bug.cgi?id=8844Two more cases: Foo opBinary(string op="/\")(Foo f) {}That is not even going to pass the lexing stage.Foo opBinary(string op)(Foo f) if (op == " ") {}What is the issue?And several other situations. Bye, bearophile
Oct 18 2012
On 10/19/2012 01:05 AM, Era Scarecrow wrote:On Thursday, 18 October 2012 at 22:07:55 UTC, Timon Gehr wrote:My suggestion was something like: error: expression 'e' of type 'S' is not of arithmetic type and it does not define opOpAssign!"+". The compiler should indicate exactly why it fails. If this is not enough, then the programmer certainly deserves the headache.On 10/18/2012 11:45 PM, bearophile wrote:Inside a function a badly named identifier becomes obvious since it outright tells you. But with regards to opOpAssign and other operator overloading I see the error message and I see the call but I don't see why it fails.There are other cases. Generally the D compiler should add some warnings that help against operator overloading mistakes.I don't think that operator overloading gives rise to distinct mistakes. For example, better error messages that just specify the expected name, as in other cases of undefined identifiers, would already fix this.Then I'll try adjusting the signature on my function, not realizing it never sees it in the first place due to misspelling.If the issue _is_ with the signature, then the compiler should tell you. That is the (secondary) job of the compiler.Maybe.. A general warning when something starts with 'op(Op)?[A-Z]''op[A-Z]'but doesn't actually qualify as any of the override-able operators? That seems sensible...That is a lot better, but what if the typo is within the first 3 characters? :o)
Oct 18 2012
On Thursday, 18 October 2012 at 23:51:44 UTC, Timon Gehr wrote:If the issue _is_ with the signature, then the compiler should tell you. That is the (secondary) job of the compiler.But not everything is parsed/compiled if it doesn't match the constraints, especially template functions. Sometimes I wish I had more information of what signatures it generated, what it compared against, and why each of them were disqualified; But that's regarding more complex stuff.That is a lot better, but what if the typo is within the first 3 characters? :o)If the beginning doesn't match 'op(Op)?[A-Z]', then you can't safely guess it was ever intended to override operators. If it has the keyword override then you know in a class it's polymorphic, however in a struct.... Hmmm... i don't know. Maybe a small suite list of tests that go through a few dozen templates and tells you what a struct qualifies for, like ranges, random access, forward/reverse, infinite. Etc. Might be more informational but if you expect you struct to do something and it doesn't qualify then you have a better idea at least of what is wrong.
Oct 18 2012
Problem solved partially. http://dpaste.dzfl.pl/e7871a01 in structs I use fix length arrays declarations, and alias its to structs, but not allowed casting to fix length arrays. I want check array length in compile time auto opBinary(string op,E)( E[DLen] b ) // fix length array if( ( op == "+" || op == "-" ) && is( E : T ) ) { // without this checking in runtime //if( DLen != b.length ) // throw new Exception("bad length"); auto res = VecT(this); foreach( i, ref m; mixin( "res." ~ DName ) ) mixin( "m " ~ op ~ "= b[i];" ); return res; } if I write E[DLen] I have errors like this Error: template opop.vec!("xyz").vec.arrayMath!("data",3LU,double,vec!("xyz")).opAssign does not match any function template declaration Error: template opop.vec!("xyz").vec.arrayMath!("data",3LU,double,vec!("xyz")).opAssign(E) if (is(E : T)) cannot deduce template function from argument types !()(int[]) but declaration like this allowed int[4] f = [1,2,3,4]; also checked in compile time assigning like this int[4] f; int[5] g; g = f; // -> Error: mismatched array lengths, 5 and 4 I think in my situation checking in compile time must be possibly, because all of template params known in compile time, but I unknown how to use it...
Oct 19 2012
On 10/19/2012 06:38 AM, Oleg wrote:Problem solved partially. http://dpaste.dzfl.pl/e7871a01 in structs I use fix length arrays declarations, and alias its to structs, but not allowed casting to fix length arrays. I want check array length in compile time auto opBinary(string op,E)( E[DLen] b ) // fix length arrayE[DLen] is good above. You can also consider taking by 'const ref' if DLen is too large. Otherwise, being value-types, fixed-length arrays normally get copied to functions.if( ( op == "+" || op == "-" ) && is( E : T ) ) { // without this checking in runtime //if( DLen != b.length ) // throw new Exception("bad length");Yes, that is not needed anymore because now it is known that b.length is always DLen.auto res = VecT(this); foreach( i, ref m; mixin( "res." ~ DName ) ) mixin( "m " ~ op ~ "= b[i];" ); return res; } if I write E[DLen] I have errors like this Error: template opop.vec!("xyz").vec.arrayMath!("data",3LU,double,vec!("xyz")).opAssign does not match any function template declaration Error: templateopop.vec!("xyz").vec.arrayMath!("data",3LU,double,vec!("xyz")).opAssign(E)if (is(E : T)) cannot deduce template function from argument types !()(int[])The problem is that array literals are slices, not fixed-length arrays. pragma(msg, typeof([1,2,3])); prints int[]but declaration like this allowed int[4] f = [1,2,3,4];Because in that case the type of f is explicitly int[4]. The following would not be: auto f = [1,2,3]; The type of f is int[]. Of course it is possible to support both arrays and slices, and avoid the check by something like isStaticArray, but your callers will have to be aware of the fact that array literals are slices. Ali
Dec 08 2012