digitalmars.D.learn - Why can't I pass a const array to a function that takes scope const
- Adnan (66/66) Feb 17 2020 https://ideone.com/lVi5Uy
- Adnan (57/63) Feb 17 2020 Okay I changed to
- Adnan (7/12) Feb 17 2020 I changed getPointPtr to following and now it works
- Simen =?UTF-8?B?S2rDpnLDpXM=?= (76/83) Feb 17 2020 I'd just finished writing a long post explaining the stuff you've
- Adnan (4/25) Feb 17 2020 Aren’t these passing by values? That’s why I used ref. Plus since
- Paul Backus (7/34) Feb 17 2020 In D, the type `T[]` is not an array like in C, but a slice,
https://ideone.com/lVi5Uy module strassens_matmul; debug { static import std; } package { ulong getRowSize(T)(T[][] mat) { return mat[0].length; } ulong getColumnSize(T)(T[][] mat) { return mat.length; } T[][] createMatrix(T)(const ulong rowSize, const ulong columnSize) { return new T[][](rowSize, columnSize); } /// row and column are 0 index-based T* getPointPtr(T)(T[][] mat, const ulong row, const ulong column) { return &mat[row][column]; } T getPointCopy(T)(T[][] mat, const ulong row, const ulong column) { return mat[row][column]; } T[][] mulIterative(T)(scope const T[][] mat1, scope const T[][] mat2) { auto result = createMatrix!T(mat1.getRowSize, mat2.getColumnSize); foreach (row; 0 .. mat1.getRowSize()) { foreach (column; 0 .. mat2.getColumnSize()) { T value; foreach (i; 0 .. mat1.getRowSize()) { value += mat1.getPointCopy(row, i) * mat2.getPointCopy(i, column); } *result.getPointPtr(row, column) = value; } } return result; } } unittest { const uint[][] matA = [[10, 20, 10], [4, 5, 6], [2, 3, 5]]; const uint[][] matB = [[3, 2, 4], [3, 3, 9], [4, 4, 2]]; const uint[][] matC = [[130, 120, 240], [51, 47, 73], [35, 33, 45]]; assert(matA.mulIterative(matB) == matC); } /// source/strassens_matmul.d(30,42): Error: template strassens_matmul.getRowSize cannot deduce function from argument types !()(const(uint[][])), candidates are: source/strassens_matmul.d(8,11): getRowSize(T)(T[][] mat) source/strassens_matmul.d(30,59): Error: template strassens_matmul.getColumnSize cannot deduce function from argument types !()(const(uint[][])), candidates are: source/strassens_matmul.d(12,11): getColumnSize(T)(T[][] mat) source/strassens_matmul.d(31,43): Error: template strassens_matmul.getRowSize cannot deduce function from argument types !()(const(uint[][])), candidates are: source/strassens_matmul.d(8,11): getRowSize(T)(T[][] mat) source/strassens_matmul.d(48,29): Error: template instance strassens_matmul.mulIterative!uint error instantiating dmd failed with exit code 1.
Feb 17 2020
On Monday, 17 February 2020 at 13:44:55 UTC, Adnan wrote:https://ideone.com/lVi5Uy module strassens_matmul; debug { static import std; } ...Okay I changed to module strassens_matmul; debug { static import std; } package { ulong getRowSize(T)(scope const T[][] mat) { return mat[0].length; } ulong getColumnSize(T)(scope const T[][] mat) { return mat.length; } T[][] createMatrix(T)(scope const ulong rowSize, scope const ulong columnSize) { return new T[][](rowSize, columnSize); } /// row and column are 0 index-based T* getPointPtr(T)(scope const ref T[][] mat, scope const ulong row, scope const ulong column) { return &mat[row][column]; } T getPointCopy(T)(scope const ref T[][] mat, scope const ulong row, scope const ulong column) { return mat[row][column]; } T[][] mulIterative(T)(scope const ref T[][] mat1, scope const T[][] mat2) { auto result = createMatrix!T(getRowSize!T(mat1), getColumnSize!T(mat2)); foreach (row; 0 .. mat1.getRowSize()) { foreach (column; 0 .. mat2.getColumnSize()) { T value; foreach (i; 0 .. mat1.getRowSize()) { value += mat1.getPointCopy(row, i) * mat2.getPointCopy(i, column); } *result.getPointPtr(row, column) = value; } } return result; } } unittest { const uint[][] matA = [[10, 20, 10], [4, 5, 6], [2, 3, 5]]; const uint[][] matB = [[3, 2, 4], [3, 3, 9], [4, 4, 2]]; const uint[][] matC = [[130, 120, 240], [51, 47, 73], [35, 33, 45]]; assert(matA.mulIterative(matB) == matC); } /// cdsa ~master: building configuration "cdsa-test-library"... source/strassens_matmul.d(22,16): Error: cannot implicitly convert expression &mat[row][column] of type const(uint)* to uint* source/strassens_matmul.d(37,36): Error: template instance strassens_matmul.getPointPtr!uint error instantiating source/strassens_matmul.d(48,29):
Feb 17 2020
On Monday, 17 February 2020 at 14:04:34 UTC, Adnan wrote:On Monday, 17 February 2020 at 13:44:55 UTC, Adnan wrote:I changed getPointPtr to following and now it works /// row and column are 0 index-based void assign(T)(ref T[][] mat, ulong row, ulong column, scope const T value) { mat[row][column] = value; }[...]Okay I changed to module strassens_matmul; [...]
Feb 17 2020
On Monday, 17 February 2020 at 14:04:34 UTC, Adnan wrote:cdsa ~master: building configuration "cdsa-test-library"... source/strassens_matmul.d(22,16): Error: cannot implicitly convert expression &mat[row][column] of type const(uint)* to uint* source/strassens_matmul.d(37,36): Error: template instance strassens_matmul.getPointPtr!uint error instantiating source/strassens_matmul.d(48,29):I'd just finished writing a long post explaining the stuff you've apparently figured out. Ah well. :p In this case, getPointPtr return T*, but takes scope const ref T[][]. Since getPointPtr always takes a mutable array, you could just get rid of const on its parameters. Alternatively, if you want to be able to use it on arrays of different constness, you could use inout: inout(T)* getPointPtr(T)(inout T[][] mat, size_t row, size_t column) { This will return a pointer to a mutable T if that's what the array holds when you call the function, const(T) if it's a const array, immutable(T) if it's immutable, and so on. The same can be done with the other functions you have. You are also somewhat overusing const, scope and ref, I'd say - you should not take an array by ref unless you plan on modifying it, which you are not doing in getPointPtr or any other of your functions. scope may be worth it, as it guarantees you won't be sending the data elsewhere. None of these are necessary on your ulongs, which are passed by value and never attempted modified. If you really like the extra guarantee that you don't accidentally modify them, feel free to keep 'const', but 'scope' on a ulong does nothing, and it's been argued it should be a compiler error. Lastly, you're using ulongs a lot, and this is mostly correct when compiling for 64-bit, but makes code fail to compile for 32-bit. Using size_t instead makes for code that works for both. All in all, I end up with this code: module strassens_matmul; debug { static import std; } package { size_t getRowSize(T)(const T[][] mat) { return mat[0].length; } size_t getColumnSize(T)(const T[][] mat) { return mat.length; } T[][] createMatrix(T)(size_t rowSize, size_t columnSize) { return new T[][](rowSize, columnSize); } /// row and column are 0 index-based inout(T)* getPointPtr(T)(inout T[][] mat, size_t row, size_t column) { return &mat[row][column]; } T getPointCopy(T)(const T[][] mat, size_t row, size_t column) { return mat[row][column]; } T[][] mulIterative(T)(const T[][] mat1, const T[][] mat2) { auto result = createMatrix!T(getRowSize!T(mat1), getColumnSize!T(mat2)); foreach (row; 0 .. mat1.getRowSize()) { foreach (column; 0 .. mat2.getColumnSize()) { T value; foreach (i; 0 .. mat1.getRowSize()) { value += mat1.getPointCopy(row, i) * mat2.getPointCopy(i, column); } *result.getPointPtr(row, column) = value; } } return result; } } unittest { const uint[][] matA = [[10, 20, 10], [4, 5, 6], [2, 3, 5]]; const uint[][] matB = [[3, 2, 4], [3, 3, 9], [4, 4, 2]]; const uint[][] matC = [[130, 120, 240], [51, 47, 73], [35, 33, 45]]; assert(matA.mulIterative(matB) == matC); } -- Simen
Feb 17 2020
On Monday, 17 February 2020 at 14:34:44 UTC, Simen Kjærås wrote:On Monday, 17 February 2020 at 14:04:34 UTC, Adnan wrote:Aren’t these passing by values? That’s why I used ref. Plus since I don’t want to change the arrays in the function scope I used const scope.//All in all, I end up with this code: module strassens_matmul package { T[][] mulIterative(T)(const T[][] mat1, const T[][] mat2) { auto result = createMatrix!T(getRowSize!T(mat1), getColumnSize!T(mat2)); foreach (row; 0 .. mat1.getRowSize()) { foreach (column; 0 .. mat2.getColumnSize()) { T value; foreach (i; 0 .. mat1.getRowSize()) { value += mat1.getPointCopy(row, i) * mat2.getPointCopy(i, column); } *result.getPointPtr(row, column) = value; } } return result; } }
Feb 17 2020
On Monday, 17 February 2020 at 20:08:24 UTC, Adnan wrote:On Monday, 17 February 2020 at 14:34:44 UTC, Simen Kjærås wrote:In D, the type `T[]` is not an array like in C, but a slice, containing a pointer to some data and an integer indicating the array's length. So when you pass it to a function by value, only the pointer and length are copied, not the data itself. You can read more about D's slices in this article: https://dlang.org/articles/d-array-article.htmlOn Monday, 17 February 2020 at 14:04:34 UTC, Adnan wrote:Aren’t these passing by values? That’s why I used ref. Plus since I don’t want to change the arrays in the function scope I used const scope.//All in all, I end up with this code: module strassens_matmul package { T[][] mulIterative(T)(const T[][] mat1, const T[][] mat2) { auto result = createMatrix!T(getRowSize!T(mat1), getColumnSize!T(mat2)); foreach (row; 0 .. mat1.getRowSize()) { foreach (column; 0 .. mat2.getColumnSize()) { T value; foreach (i; 0 .. mat1.getRowSize()) { value += mat1.getPointCopy(row, i) * mat2.getPointCopy(i, column); } *result.getPointPtr(row, column) = value; } } return result; } }
Feb 17 2020