Re: How to pass in reference a fixed array in parameter

2024-06-05 Thread Eric P626 via Digitalmars-d-learn

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 ?

2024-06-05 Thread Basile B. via Digitalmars-d-learn

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

2024-06-05 Thread bauss via Digitalmars-d-learn

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

2024-06-05 Thread evilrat via Digitalmars-d-learn

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

2024-06-05 Thread Nick Treleaven via Digitalmars-d-learn

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

2024-06-05 Thread Nick Treleaven via Digitalmars-d-learn

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

2024-06-05 Thread Nick Treleaven via Digitalmars-d-learn

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

2024-06-05 Thread Nick Treleaven via Digitalmars-d-learn

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

2024-06-05 Thread Kagamin via Digitalmars-d-learn

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

2024-06-05 Thread Nick Treleaven via Digitalmars-d-learn

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

2024-06-05 Thread Kagamin via Digitalmars-d-learn

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

2024-06-05 Thread evilrat via Digitalmars-d-learn

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 ?

2024-06-05 Thread Nick Treleaven via Digitalmars-d-learn

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 ?

2024-06-05 Thread Kagamin via Digitalmars-d-learn

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 ?

2024-06-05 Thread Dukc via Digitalmars-d-learn

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();
```