Re: bool passed by ref, safe or not ?

2024-06-06 Thread Quirin Schroll via Digitalmars-d-learn

On Wednesday, 5 June 2024 at 18:31:12 UTC, Basile B. wrote:

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.


I don’t think there’s any meaningful difference. If a program has 
UB, it can do anything, including corrupt memory. If a program 
corrupts memory, that’s UB. `@safe` means UB-free, which includes 
free of memory corruption.


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

2024-06-06 Thread Quirin Schroll via Digitalmars-d-learn

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.


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.


First things first, put `@safe:` on the top of the file or put 
`@safe` at the end of every function declarator. It makes 
anything that could be undefined behavior an error:

```d
void main() @safe
{
writeln("Maze generation demo");

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

}

// change to: ( const ref s_cell [5][5] maze )
void print_maze ( s_cell [][] maze ) @safe
{
}
```

A `T[]` is a pointer–length pair, aka. a slice. A `T[n]` is a 
block of `n` values of type `T`. Assuming you know a thing or two 
about C, a `T[n]` converts to a `T[]` like an `int` converts to a 
`long`: It’s lossless and safe, but not pointer compatible.


For the same reason an `int*` can’t convert to a `long*`, a 
`T[m][n]` can’t convert to a `T[][]`.


Also, if you’re new, be aware some people call slices “dynamic 
arrays,” which is really misleading sometimes.


* If a function writes a maze, pass the maze by `ref`. Note that 
`ref` is not part of the parameter’s type (as in C++), but a 
property of the parameter akin to its type.
* If a function only reads a maze, pass the maze by `const ref`; 
or `in` using the command-line option `-preview=in` which: allows 
rvalues and doesn’t bind by reference if the object bound is 
small and trivial to copy.


Unintentional sharing?

2024-06-06 Thread Andy Valencia via Digitalmars-d-learn
I was using instance initialization which allocated a new object. 
 My intention was this initialization would happen per-instance, 
but all instances appear to share the same sub-object?  That is, 
f1.b and f2.b appear to point to a single object?  Obviously I 
moved the new into the initializer code, but I hadn't appreciated 
how initial instance values were calculated once.  Interestingly, 
this makes it similar to how Python calculates default argument 
values for functions.


class Bar {
int z = 3;
}

class Foo {
auto b = new Bar();
}

void
main() {
import std.stdio : writeln;

auto f1 = new Foo(), f2 = new Foo();
f1.b.z = 0;
writeln(f2.b.z);
}


Re: Unintentional sharing?

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

On Thursday, 6 June 2024 at 17:49:39 UTC, Andy Valencia wrote:
I was using instance initialization which allocated a new 
object.  My intention was this initialization would happen 
per-instance, but all instances appear to share the same 
sub-object?  That is, f1.b and f2.b appear to point to a single 
object?  Obviously I moved the new into the initializer code, 
but I hadn't appreciated how initial instance values were 
calculated once.  Interestingly, this makes it similar to how 
Python calculates default argument values for functions.


class Bar {
int z = 3;
}

class Foo {
auto b = new Bar();
}

void
main() {
import std.stdio : writeln;

auto f1 = new Foo(), f2 = new Foo();
f1.b.z = 0;
writeln(f2.b.z);
}


What you are seeing here is indeed sharing reference.
It happens because type initializer sets fields after memory 
allocation but before constructor call, and so since it is using 
value known at compile time all instances will have share same 
reference.


https://dlang.org/spec/class.html#constructors


Re: Unintentional sharing?

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

On Thursday, 6 June 2024 at 17:49:39 UTC, Andy Valencia wrote:
I was using instance initialization which allocated a new 
object.  My intention was this initialization would happen 
per-instance, but all instances appear to share the same 
sub-object?  That is, f1.b and f2.b appear to point to a single 
object?  Obviously I moved the new into the initializer code, 
but I hadn't appreciated how initial instance values were 
calculated once.  Interestingly, this makes it similar to how 
Python calculates default argument values for functions.


class Bar {
int z = 3;
}

class Foo {
auto b = new Bar();
}

void
main() {
import std.stdio : writeln;

auto f1 = new Foo(), f2 = new Foo();
f1.b.z = 0;
writeln(f2.b.z);
}


This is a long standing issue:
https://issues.dlang.org/show_bug.cgi?id=2947

I think with the next edition we can disallow (tail) mutable 
initializers for fields (and TLS globals too).


Re: Unintentional sharing?

2024-06-06 Thread H. S. Teoh via Digitalmars-d-learn
On Thu, Jun 06, 2024 at 05:49:39PM +, Andy Valencia via Digitalmars-d-learn 
wrote:
> I was using instance initialization which allocated a new object.  My
> intention was this initialization would happen per-instance, but all
> instances appear to share the same sub-object?  That is, f1.b and f2.b
> appear to point to a single object?
[...]

Yes, if you want a per-instance object, you need to do it in this(), not
in the initializer.


--T