Why can't I pass a const array to a function that takes scope const arrays?

Simen Kjærås simen.kjaras at gmail.com
Mon Feb 17 14:34:44 UTC 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


More information about the Digitalmars-d-learn mailing list