Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 10:36:50 UTC, Nick Treleaven wrote: ```d import std.stdio; alias s_cell = int; void main() { writeln("Maze generation demo"); s_cell [5][5] maze; int n; foreach (i, row; maze) foreach (j, col; row) maze[i][j] = n++; s_cell[][5] slices; foreach (i, _; maze) slices[i] = maze[i]; print_maze (slices); } void print_maze ( s_cell [][] maze ) { foreach (a; maze) a.writeln(); } ``` Thanks for the feedback Almost all my projects works intensively with multiple dimensions arrays. So I want to know the best way to manage multi dimensional arrays. I guess the best solution so far are: 1) Only use dynamic arrays. 2) Use a single dimension array, and compute the index value from x,y,z coordinates (Makes dynamic allocation easier). This solution could work well with pointers too. 3) Make my own data structure or class containing the array. Allowing to pass the structure/class by reference. Could allow encapsulating single or multi dimensional arrays. About .ptr, the documentation page state that: ~~~ The .ptr property for static and dynamic arrays will give the address of the first element in the array: ~~~ So I assumed that the following expressions where equivalent, but I guess the multiple dimensions do complicate things: ~~~ array.ptr == &array == &array[0] ~~~ So ommitting the "ref" keyword it's like if the data was read only even if the variable is not passed by value. That means that this signature cannot modify the content of the 2D array: ~~~ void print_maze ( s_cell [][] maze ) ~~~ For the create_maze() function, I would need to use the follwing signature since it changes the content of the array. ~~~ void print_maze ( ref s_cell [][] maze ) ~~~ I imagine `a.writeln();` is the same as `writeln(a);` ? Your foreach loops look better than mine. Here is the code I have been using to print the maze. ~~~ void print_maze ( s_cell [][] maze ) { //print top row, assume full foreach ( cell; maze[0] ) write("+---"); writeln("+"); for ( int y = 0; y < maze.length; y++) { //print content write("|"); //assume edge is always full for ( int x = 0; x < maze[y].length; x++) { write(" "); write( maze[y][x].east ? "|": " "); } writeln(); foreach ( cell; maze[y] ) write( cell.south ? "+---" : " " ); writeln("+"); } } ~~~ your iteration version is more neat: ~~~ foreach (i, row; maze) foreach (j, col; row) maze[i][j] = n++; ~~~ I like that using 2 variables (i,row) or (j,col) allow to access the variable later as a element in a collection or as an index. It's more flexible. I'll guess I'll need to read more code to avoid programming too much old school (^_^).
Re: bool passed by ref, safe or not ?
On Wednesday, 5 June 2024 at 01:18:06 UTC, Paul Backus wrote: On Tuesday, 4 June 2024 at 16:58:50 UTC, Basile B. wrote: ```d void main(string[] args) { ushort a = 0b; bool* b = cast(bool*)&a; setIt(*b); assert(a == 0b); // what actually happens assert(a == 0b1110); // what would be safe } ``` [...] Do I corrupt memory here or not ? Is that a safety violation ? `cast(bool*)&a` is a safety violation. The only [safe values][1] for a `bool` are 0 (false) and 1 (true). By creating a `bool*` that points to a different value, you have violated the language's safety invariants. Because of this, operations that would normally be safe (reading or writing through the `bool*`) may now result in undefined behavior. [1]: https://dlang.org/spec/function.html#safe-values Obviously the topic was created because of the recent move D made. Sorry for the "catchy" aspect BTW. Now I remember that D safety is unrelated to undefined behaviors.
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 06:22:34 UTC, Eric P626 wrote: I tried the following signatures with the ref keyword and it did not change anything: ~~~ void print_maze ( ref s_cell maze ) void print_maze ( ref s_cell [][] maze ) ~~~ From what I found, arrays passed in parameters are always passed by reference. So the ref keyword seems pointless. There is one useful functionality about the ref keyword when passing arrays, it is that you can change the original array reference to another array reference. Ex. ``` void foo(ref int[] x) { x = [1,2,3]; } void bar(int[] y) { y = [1,2,3]; } void main() { auto x = [0,0,0]; auto y = [1,1,1]; foo(x); bar(y); writeln(x); writeln(y); } ``` The output of the program is: ``` [1, 2, 3] [1, 1, 1] ``` Of course in your case this doesn't matter, but just wanted to point out that adding ref to array parameters actually pose a function.
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 11:27:32 UTC, Nick Treleaven wrote: On Wednesday, 5 June 2024 at 09:24:23 UTC, evilrat wrote: for simple cases like this it might work, but 2d array is not even contiguous, A 2D static array is contiguous: https://dlang.org/spec/arrays.html#rectangular-arrays D static arrays, while using the same syntax, are implemented as a fixed rectangular layout in a contiguous block of memory Yeah ok, i might have messed up with columns last time, but it works. ```d int[5][5] test; foreach(i; 0..5) { foreach(j; 0..5) { test[i][j] = i * 5 + j; } } foreach(i; 0..25) { assert(test[0].ptr[i] == i); } ```
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 09:24:23 UTC, evilrat wrote: for simple cases like this it might work, but 2d array is not even contiguous, A 2D static array is contiguous: https://dlang.org/spec/arrays.html#rectangular-arrays D static arrays, while using the same syntax, are implemented as a fixed rectangular layout in a contiguous block of memory
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 10:27:47 UTC, Nick Treleaven wrote: foreach (i, row; maze) slices[i] = row; Sorry that assignment was wrong (edited at last minute). Fixed: ```d import std.stdio; alias s_cell = int; void main() { writeln("Maze generation demo"); s_cell [5][5] maze; int n; foreach (i, row; maze) foreach (j, col; row) maze[i][j] = n++; s_cell[][5] slices; foreach (i, _; maze) slices[i] = maze[i]; print_maze (slices); } void print_maze ( s_cell [][] maze ) { foreach (a; maze) a.writeln(); } ```
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 10:27:47 UTC, Nick Treleaven wrote: //~ void print_maze ( s_cell [][] maze... ) I meant to delete that line!
Re: How to pass in reference a fixed array in parameter
On Tuesday, 4 June 2024 at 12:22:23 UTC, Eric P626 wrote: ~~~ void main() { writeln("Maze generation demo"); s_cell [5][5] maze; print_maze (maze); } void print_maze ( s_cell [][] maze ) { } ~~~ This is how to do it without GC allocations (I have used `int` instead for demo purposes): ```d import std.stdio; alias s_cell = int; void main() { writeln("Maze generation demo"); s_cell [5][5] maze = [0, 1, 2, 3, 4]; s_cell[][5] slices; // static array of 5 slices foreach (i, row; maze) slices[i] = row; print_maze (slices); } //~ void print_maze ( s_cell [][] maze... ) void print_maze ( s_cell [][] maze ) { foreach (a; maze) a.writeln(); } ```
Re: How to pass in reference a fixed array in parameter
With accessor: ``` void main() { s_cell[] maze=make(5,5); s_cell a=maze.get(1,2); print_maze(maze); } void print_maze(s_cell[] maze) { } s_cell[] make(int width, int height) { return new s_cell[width*height]; } s_cell get(s_cell[] maze, int x, int y) { return maze[5*y+x]; //oops } ``` looks like you need to store the maze width somewhere.
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 06:22:34 UTC, Eric P626 wrote: Now according to the book, it's possible to assign a slice from a fixed array. This code will compile: ~~~ int[12] monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; int[] a_slice = monthDays; ~~~ The element types are both int, so the compiler can slice the static array. As if you had written `a_slice = monthDays[];`. How come the assignment does not work when passing a parameter. I tried the following and it failed: ~~~ s_cell [5][5] maze; The element type is s_cell[5]. s_cell [][] sliced_maze = maze; The element type of sliced_maze is s_cell[], so the element types are incompatible. ~~~ void print_maze ( ref s_cell maze ) void print_maze ( ref s_cell [][] maze ) ~~~ From what I found, arrays passed in parameters are always passed by reference. So the ref keyword seems pointless. You don't need `ref` to be able to read the array length and elements. However, if you want to modify the array length, and have it affect the caller's dynamic array, you need `ref`. --- The only solution left is to use pointers. But even this does not seems to work as in C. I created a function with different pointer signature and they all fails. Normally in C, this would have worked: ~~~ s_cell [5][5] maze; create_maze(&maze); Pass `&maze[0][0]` instead. ~~~ Error: function `mprmaze.create_maze(s_cell[][]* maze)` is not callable using argument types `(s_cell[5][5]*)` cannot pass argument `& maze` of type `s_cell[5][5]*` to parameter `s_cell[][]* maze` ~~~ s_cell[5][5] cannot implicitly convert to s_cell[][]. Now I think it expect a 2D array of pointers instead of a pointer on a 2D array. It's also not clear if there is a difference between those 2 notations: ~~~ &maze maze.ptr ~~~ &maze is a pointer to s_cell[5][5]. maze.ptr is a pointer to s_cell[5]. `.ptr` means a pointer to the first element of the array.
Re: How to pass in reference a fixed array in parameter
On Tuesday, 4 June 2024 at 12:22:23 UTC, Eric P626 wrote: I try to create a 2D array of fixed length and pass it in parameter as a reference. Normally, in C, I would have used a pointer as parameter, and pass the address of the array. Not obvious what you're trying to do. How would you do it in C? Use one dimensional array? You can use one dimensional array in D too. If dimensions of the maze are dynamic, you just write the maze creation function that allocates the maze as you want. In simple case: ``` void main() { writeln("Maze generation demo"); s_cell [5][5] maze; print_maze (maze); } void print_maze (ref s_cell [5][5] maze ) { } ``` With factory: ``` void main() { s_cell[][] maze=make(5,5); print_maze(maze); } void print_maze(s_cell[][] maze) { } s_cell[][] make(int width, int height) { } ```
Re: How to pass in reference a fixed array in parameter
On Wednesday, 5 June 2024 at 06:22:34 UTC, Eric P626 wrote: On Tuesday, 4 June 2024 at 16:19:39 UTC, Andy Valencia wrote: On Tuesday, 4 June 2024 at 12:22:23 UTC, Eric P626 wrote: Thanks for the comments. So far, I only managed to make it work by creating a dynamic array and keeping the same signature: ~~~ void main() { s_cell [][] maze = new s_cell[][](5,5); print_maze (maze); } void print_maze ( s_cell [][] maze ) { } ~~~ Now according to the book, it's possible to assign a slice from a fixed array. This code will compile: ~~~ int[12] monthDays = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; int[] a_slice = monthDays; ~~~ for simple cases like this it might work, but 2d array is not even contiguous, simpler case like s_cell[5][] might work too. How come the assignment does not work when passing a parameter. I tried the following and it failed: ~~~ s_cell [5][5] maze; s_cell [][] sliced_maze = maze; ~~~ with this message: ~~~ Error: cannot implicitly convert expression `maze` of type `s_cell[5][5]` to `s_cell[][]` ~~~ Is it because it's a 2D array (slice of slice)? I need to manually copy each slice manually, or use a utility function to do the copy? This is why it cannot auto-magically do it with just when passing a parameter. very likely this is the only solution - make a dynamic array by copying all elements. there was few old bug tracker issues discussed wrt to static arrays and join function but there is seems to be no agreement so far. ~~~ Error: function `mprmaze.create_maze(s_cell[][]* maze)` is not callable using argument types `(s_cell[5][5]*)` cannot pass argument `& maze` of type `s_cell[5][5]*` to parameter `s_cell[][]* maze` ~~~ Now I think it expect a 2D array of pointers instead of a pointer on a 2D array. It's also not clear if there is a difference between those 2 notations: ~~~ &maze maze.ptr ~~~ there is, array itself is a tuple of length and pointer, the .ptr notation is just the data location, this is what you usually pass to C functions and not &maze itself. to sum up, i wasn't able to make fixed-size arrays to work with dynamic arrays without making a copy, and I don't think this will change in the future because of various reasons including type system limitations and binary object formats. so if you really absolutely need static arrays for example to avoid GC allocations in hot path than you need to make function that takes fixed size array. in addition to that spec (https://dlang.org/spec/arrays.html#static-arrays) says static arrays is passed by value, unlike dynamic arrays that even when passed as length-and-pointer tuple will allow writing back to original data.
Re: bool passed by ref, safe or not ?
On Wednesday, 5 June 2024 at 09:09:40 UTC, Kagamin wrote: On Wednesday, 5 June 2024 at 01:18:06 UTC, Paul Backus wrote: The only safe values for a `bool` are 0 (false) and 1 (true). AFAIK that was fixed and now full 8-bit range is safe. `cast(bool) someByte` is fine - that doesn't reinterpret the bit representation. The problem is certain values such as `0x2` for the byte representation can cause the boolean to be both true and false: https://issues.dlang.org/show_bug.cgi?id=20148#c3 Void initialization of bool and bool union fields are now deprecated in @safe functions as of 2.109. There is a remaining case of casting an array to bool[], which I am working on disallowing in @safe.
Re: bool passed by ref, safe or not ?
On Wednesday, 5 June 2024 at 01:18:06 UTC, Paul Backus wrote: The only safe values for a `bool` are 0 (false) and 1 (true). AFAIK that was fixed and now full 8-bit range is safe.
Re: bool passed by ref, safe or not ?
Basile B. kirjoitti 4.6.2024 klo 19.58: I understand that the notion of `bool` doesn't exist on X86, hence what will be used is rather an instruction that write on the lower 8 bits, but with a 7 bits corruption. Do I corrupt memory here or not ? Is that a safety violation ? Viewing a valid boolean as an integer is still valid. Bit pattern of `false` is 0b_, and bit pattern of `true` is `0b_0001`. And even if the boolean is invalid, viewing it as an integer is probably valid if it was assigned to as an integer and not as an invalid boolean. There's a related case though where the situation is unclear. How do `ubytes` other than 1 or 0, when viewed as bools? We probably can't say it's undefined behaviour, since it is allowed in `@safe`. How I would define it, is that it's unspecific behaviour. That is if you have ```D bool* unspecified = cast(bool*) new ubyte(0xff); ``` then ``` // same as void-initialising bool a = *unspecified; // also same as void-initialising ubyte b = *unspecified; // Reliably 0xff. It's using the memory slot as bool that makes it unspecified, but what's in the memory slot is not affected. ubyte c = * cast(ubyte*) unspecified; // Unspecified which happens. One and only one must happen though. if (*unspecified) fun() else gun(); // Should this be required to call the same function as above? I'm not sure. if (*unspecified) fun() else gun(); ```