Jump to page: 1 2
Thread overview
How to pass in reference a fixed array in parameter
Jun 04
Eric P626
Jun 04
evilrat
Jun 05
Eric P626
Jun 05
evilrat
Jun 05
evilrat
Jun 05
bauss
Jun 05
Kagamin
Jun 05
Kagamin
Jun 06
Eric P626
June 04

I am currently trying to learn how to program in D. I thought that I could start by trying some maze generation algorithms. I have a maze stored as 2D array of structure defined as follow which keep tracks of wall positions:

struct s_cell
{
   bool north = true;
   bool east = true;
   bool south = true;
   bool west = true;
}

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. Here, I thought it would have been easier just to pass a slice of the array, since a slice is a reference to the original array. So I wrote the signature like this:

void main()
{  writeln("Maze generation demo");

   s_cell [5][5] maze;
   print_maze (maze);

}

void print_maze ( s_cell [][] maze )
{
}

My idea is that print_maze use a slice of what ever is sent in parameter. Unfortunately, I get the following error message:

Error: function `mprmaze.print_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`

I tried to find a solution on the internet, but could not find anything, I stumble a lot on threads about Go or Rust language even if I specify "d language" in my search.

Else is there other ways to pass an array as reference using parameter modifiers like: ref,in,out ...

Else, can it be done the C way using pointers?

Thank you.

June 04

On Tuesday, 4 June 2024 at 12:22:23 UTC, Eric P626 wrote:

>

I am currently trying to learn how to program in D. I thought that I could start by trying some maze generation algorithms. I have a maze stored as 2D array of structure defined as follow which keep tracks of wall positions:

struct s_cell
{
   bool north = true;
   bool east = true;
   bool south = true;
   bool west = true;
}

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. Here, I thought it would have been easier just to pass a slice of the array, since a slice is a reference to the original array. So I wrote the signature like this:

void main()
{  writeln("Maze generation demo");

   s_cell [5][5] maze;
   print_maze (maze);

}

void print_maze ( s_cell [][] maze )
{
}

My idea is that print_maze use a slice of what ever is sent in parameter. Unfortunately, I get the following error message:

Error: function `mprmaze.print_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`

I tried to find a solution on the internet, but could not find anything, I stumble a lot on threads about Go or Rust language even if I specify "d language" in my search.

You have declared static array here, they cannot be implicitly converted to dynamic arrays.

It is not very obvious but it is a part of language design to avoid unnecessary GC allocations and for C compatibility reasons in some cases (e.g. strings known at compile implicitly has null appended to it to be able to pass pointer as is to C functions).

IIRC you can explicitly cast it to s_cell[][] to make it work but it will allocate new array when you append to it.

>

Else is there other ways to pass an array as reference using parameter modifiers like: ref,in,out ...

ref is exactly for that.

>

Else, can it be done the C way using pointers?

absolutely, even ref behind the scenes will basically do the same thing anyway.

June 04

On Tuesday, 4 June 2024 at 12:22:23 UTC, Eric P626 wrote:

>

I tried to find a solution on the internet, but could not find anything, I stumble a lot on threads about Go or Rust language even if I specify "d language" in my search.

Aside from the excellent answer already present, I wanted to mention that searching with "dlang" has helped target my searches.

Welcome to D! (From another newbie.)
Andy

June 05

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:

>

I tried to find a solution on the internet, but could not find anything, I stumble a lot on threads about Go or Rust language even if I specify "d language" in my search.

Aside from the excellent answer already present, I wanted to mention that searching with "dlang" has helped target my searches.

Welcome to D! (From another newbie.)
Andy

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;

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.

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.


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

void create_maze ( s_cell *maze)
{
}

I get the following error

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`

But I get the idea of ambiguity, is the pointer pointing on a single cell, or an array of cells, so there might need a way to specify that it's not just an elements. I tried this:

s_cell [5][5] maze;
create_maze(&maze);

    void create_maze ( s_cell [][]*maze)
    {
    }

and get this error

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

Do you have a code sample on how to pass a 2D array by pointer?

So far, the pointer solution seems like the only method that should be compatible with both fixed and dynamic arrays unless I am mistaken.

June 05

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.

June 05

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)
{
}
June 05

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.

June 05

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.

June 05

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):

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();
}
June 05

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!

« First   ‹ Prev
1 2