digitalmars.D.learn - std.conv.to!string(array), strange compile error
I've got this strange compile error using std.conv.to!string(double[3]) - or any static array type. It's called in toString override function of a template matrix class, I'm building as a D learning project. Here is the toString method: override string toString() const { string outs; outs ~= "["; for (size_t i = 0; i < rows; ++i) { outs ~= this.opIndex(i, 0).to!string; for (size_t j = 1; j < cols; ++j) { outs~= ", " ~ this.opIndex(i, j).to!string; } if (i == rows - 1) // last row outs ~= "]"; else outs ~= ";\n"; } return outs; } And here is the opIndex (const version): const(T) opIndex(ulong r, ulong c) const in { assert(r < _rows && c < _cols); } body { return _begin[c*_strides[1] + r*_strides[0]]; } Error occurs on lines with "this.opIndex().to!string", when template type is static array, e.g. double[3]: source/matrix.d(248,30): Error: template std.conv.to cannot deduce function from argument types !(string)(const(double[3])), candidates are: /usr/include/dlang/dmd/std/conv.d(293,1): std.conv.to(T) source/matrix.d(251,37): Error: template std.conv.to cannot deduce function from argument types !(string)(const(double[3])), candidates are: /usr/include/dlang/dmd/std/conv.d(293,1): std.conv.to(T) source/main.d(17,2): Error: template instance matrix.Matrix!(double[3]) error instantiating Lines 248 and 251 are the opIndex.to!string calls. Anyhow, I've changed opIndex() calls in the toString with matrix array indexing implementation (_begin[row*col_stride + col*item_stride]), and the conversion works properly (as it should on any array type, and gives normal output). So I've made a little test with compile-time messages: override string toString() const { string outs; outs ~= "["; pragma(msg, typeof(_begin[0]).stringof); pragma(msg, typeof(this.opIndex(0, 0)).stringof); this._begin[0].to!string; (this.opIndex(0, 0)).to!string; ..... And here's the compile output: const(double[3]) const(double[3]) source/matrix.d(250): Error: template std.conv.to cannot deduce function from argument types !(string)(const(double[3])), candidates are: /usr/include/dlang/dmd/std/conv.d(293): std.conv.to(T) Line 250 is opIndex().to!string, line above compiles ok. So even opIndex has the same return type as the array itself, to!string produces compile error on the opIndex.to!string call, and on the array.to!string does not. Could this be a bug in the compiler, or am I doing something wrong with the opIndex (or any other) method declaration? System is x64 Manjaro linux(arch based distro), compiler is dmd v2.069 (up-to-date from AUR, as libphobos is), and I have no other D compilers installed. Im' not sure how to check exact version of the libphobos - if anyone can tell me how to check it, please tell me, and I'll post it. Any other suggestion about above code is welcome! Thanks, Relja Ljubobratovic
Nov 14 2015
On Saturday, 14 November 2015 at 12:46:21 UTC, Relja wrote:I've got this strange compile error using std.conv.to!string(double[3]) - or any static array type. It's called in toString override function of a template matrix class, I'm building as a D learning project. [...]Maybe try to use a full slice after a 'static if' in case the template type is static array: -- { ElementType!T[] something; static if (isStaticArray!T) something = value[]; // slice to get a dyn array else something = value; // already a dyn array } -- and you work on something when it only works on dyn array. You can also slice the whole static array each time the problem occurrs
Nov 14 2015
On Saturday, 14 November 2015 at 12:55:52 UTC, BBaz wrote:On Saturday, 14 November 2015 at 12:46:21 UTC, Relja wrote:I'm not sure if I understand you fully, but I think you misunderstood me - std.conv.to!string() works on a static array, when called directly on the array object, but gives the compile error when called on the returning object from a function. Here is simpler example, which shows the same compile error: import std.conv; float[3] getFloat3() { return [1, 2, 3]; } void main() { getFloat3().to!string; // does not compile (new float[3]).to!string; // compiles } On this example, compiler error message is the same as above: source/app.d(10,12): Error: template std.conv.to cannot deduce function from argument types !(string)(float[3]), candidates are: /usr/include/dlang/dmd/std/conv.d(293,1): std.conv.to(T) dmd failed with exit code 1. But then again, your suggestion got me to try this: getFloat3()[].to!string; This does compile! Can somebody elaborate, and tell us whats going on here? I feel that this does not solve my issue, but only makes me stay away from calling std.conv.to in this way. Thanks, ReljaI've got this strange compile error using std.conv.to!string(double[3]) - or any static array type. It's called in toString override function of a template matrix class, I'm building as a D learning project. [...]Maybe try to use a full slice after a 'static if' in case the template type is static array: -- { ElementType!T[] something; static if (isStaticArray!T) something = value[]; // slice to get a dyn array else something = value; // already a dyn array } -- and you work on something when it only works on dyn array. You can also slice the whole static array each time the problem occurrs
Nov 14 2015
On 14.11.2015 15:17, Relja wrote:- std.conv.to!string() works on a static array, when called directly on the array object, but gives the compile error when called on the returning object from a function.[...]void main() { getFloat3().to!string; // does not compile (new float[3]).to!string; // compiles }`new float[3]` is not a static array. Its type is not `float[3]`, it's `float[]`.
Nov 14 2015
On Saturday, 14 November 2015 at 14:30:06 UTC, anonymous wrote:On 14.11.2015 15:17, Relja wrote:Oh, my bad, sorry. No mather, issue still stands: float[3] array; array.to!string; // compiles- std.conv.to!string() works on a static array, when called directly on the array object, but gives the compile error when called on the returning object from a function.[...]void main() { getFloat3().to!string; // does not compile (new float[3]).to!string; // compiles }`new float[3]` is not a static array. Its type is not `float[3]`, it's `float[]`.
Nov 14 2015
On 14.11.2015 15:40, Relja wrote:float[3] array; array.to!string; // compilesAlright, full test case: ---- import std.conv; float[3] getFloat3() { return [1, 2, 3]; } void main() { getFloat3().to!string; // does not compile float[3] a; a.to!string; // compiles } ---- Yeah, that's odd. Looking at std.conv, `to` is this [1]: ---- template to(T) { T to(A...)(A args) if (!isRawStaticArray!A) { return toImpl!T(args); } // Fix issue 6175 T to(S)(ref S arg) if (isRawStaticArray!S) { return toImpl!T(arg); } } ---- So static arrays are taken by reference. That explains why return values from functions are rejected: they're rvalues and can't be passed by reference. Apparently, that oddity is a fix for issue 6175 [2] which seems to be about `to` returning a slice of a local variable (which is bad). I don't know the details of the issue or the fix, but I've got a feeling that there must be a better fix. Taking the data by reference, but otherwise doing the same as before would mean that `to` simply slices a static array when asked to make a dynamic array of it, rather than copying the data. And indeed, that seems to be the case: ---- float[] f() { import std.conv; float[3] a = [1, 2, 3]; return a.to!(float[]); } void main() { auto a = f(); import std.stdio; writeln(a); /* prints garbage */ } ---- I don't know if that's considered acceptable. I'm not a fan. [1] https://github.com/D-Programming-Language/phobos/blob/48d57e36e74379291a52087fcd1aa0dc19ff9a70/std/conv.d#L293-L307 [2] https://issues.dlang.org/show_bug.cgi?id=6175
Nov 14 2015
On Saturday, 14 November 2015 at 18:52:54 UTC, anonymous wrote:On 14.11.2015 15:40, Relja wrote:Great explanation! Thank you![...]Alright, full test case: ---- import std.conv; [...]
Nov 14 2015