Re: TIL: statically initializing an Associative Array

2024-05-06 Thread Andy Valencia via Digitalmars-d-learn
On Tuesday, 7 May 2024 at 01:14:24 UTC, Steven Schveighoffer 
wrote:

On Tuesday, 7 May 2024 at 00:10:27 UTC, Andy Valencia wrote:
I had a set of default error messages to go with error code 
numbers, and did something along the lines of:


string[uint] error_text = [
400: "A message",
401: "A different message"
];

and got "expression  is not a constant"

...
This was fixed [in 
2.106.0](https://dlang.org/changelog/2.106.0.html#dmd.static-assoc-array)


 please upgrade your compiler.


I'm using ldc2 from Debian stable; great news that it's fixed as 
of late 2023.  I'll probably live with my workaround, but it's 
good to know that it's a bug which has been resolved.


Thank you!
Andy



Re: TIL: statically initializing an Associative Array

2024-05-06 Thread Steven Schveighoffer via Digitalmars-d-learn

On Tuesday, 7 May 2024 at 00:10:27 UTC, Andy Valencia wrote:
I had a set of default error messages to go with error code 
numbers, and did something along the lines of:


string[uint] error_text = [
400: "A message",
401: "A different message"
];

and got "expression  is not a constant"

I eventually found this discussion:
https://issues.dlang.org/show_bug.cgi?id=6238

I understand that it's problematic, but a message which makes 
it clearer that compile-time initialization of global AA's are 
not supported?  Because it cost me about a half hour trying to 
figure out what I was doing wrong.


This error message was changed in 2.101.x (unsure which point 
release):


```
onlineapp.d(1): Error: static initializations of associative 
arrays is not allowed.
onlineapp.d(1):associative arrays must be initialized at 
runtime: 
https://dlang.org/spec/hash-map.html#runtime_initialization

```



(My workaround was to initialize the data structure once during 
app startup.)


This was fixed [in 
2.106.0](https://dlang.org/changelog/2.106.0.html#dmd.static-assoc-array)


 please upgrade your compiler.

-Steve


Re: TIL: statically initializing an Associative Array

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

On Tuesday, 7 May 2024 at 01:02:04 UTC, matheus wrote:

On Tuesday, 7 May 2024 at 00:10:27 UTC, Andy Valencia wrote:
...
Based on what I understood and that issue, I think it was fixed:
...


By the way it works as immutable too.

Matheus.




Re: TIL: statically initializing an Associative Array

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

On Tuesday, 7 May 2024 at 00:10:27 UTC, Andy Valencia wrote:
I had a set of default error messages to go with error code 
numbers, and did something along the lines of:


string[uint] error_text = [
400: "A message",
401: "A different message"
];

and got "expression  is not a constant"

I eventually found this discussion:
https://issues.dlang.org/show_bug.cgi?id=6238

I understand that it's problematic, but a message which makes 
it clearer that compile-time initialization of global AA's are 
not supported?  Because it cost me about a half hour trying to 
figure out what I was doing wrong.


(My workaround was to initialize the data structure once during 
app startup.)


Based on what I understood and that issue, I think it was fixed:

import std.stdio;

string[uint] aa1 = [1:"ABC",2:"DEF"];

void main(){
auto aa2 = ['A':1,'B':2];

writeln(aa1[1]);
writeln(aa1[2]);
writeln(aa2['A']);
writeln(aa2['B']);
}

Prints:

ABC
DEF
1
2

Matheus.


TIL: statically initializing an Associative Array

2024-05-06 Thread Andy Valencia via Digitalmars-d-learn
I had a set of default error messages to go with error code 
numbers, and did something along the lines of:


string[uint] error_text = [
400: "A message",
401: "A different message"
];

and got "expression  is not a constant"

I eventually found this discussion:
https://issues.dlang.org/show_bug.cgi?id=6238

I understand that it's problematic, but a message which makes it 
clearer that compile-time initialization of global AA's are not 
supported?  Because it cost me about a half hour trying to figure 
out what I was doing wrong.


(My workaround was to initialize the data structure once during 
app startup.)




Re: Why is Phobos `Flag` so overthought ?

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

On Monday, 6 May 2024 at 18:06:53 UTC, Julian Fondren wrote:

On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:

I think this just works:

```d
enum Flag : bool
{
no,
yes
}

alias AllowVancancy = Flag; // example usage
```


```d
import std.stdio : writeln;

enum Flag : bool { no, yes }
alias Traditional = Flag;
alias Color = Flag;

void hello(Traditional traditional, Color color) {
if (traditional && color) {
writeln("\x1b[31;1mhello world\x1b[0m");
} else if (traditional && !color) {
writeln("hello world");
} else if (!traditional && color) {
writeln("\x1b[31;1mHello, world!\x1b[0m");
} else {
writeln("Hello, world!");
}
}

void main() {
hello(Color.yes, Traditional.yes); // this is wrong, but 
accepted

}
```


Ah yes I see, strongly typed bools.
Thanks 👍.




Re: Why is Phobos `Flag` so overthought ?

2024-05-06 Thread Julian Fondren via Digitalmars-d-learn

On Monday, 6 May 2024 at 17:55:49 UTC, user1234 wrote:

I think this just works:

```d
enum Flag : bool
{
no,
yes
}

alias AllowVancancy = Flag; // example usage
```


```d
import std.stdio : writeln;

enum Flag : bool { no, yes }
alias Traditional = Flag;
alias Color = Flag;

void hello(Traditional traditional, Color color) {
if (traditional && color) {
writeln("\x1b[31;1mhello world\x1b[0m");
} else if (traditional && !color) {
writeln("hello world");
} else if (!traditional && color) {
writeln("\x1b[31;1mHello, world!\x1b[0m");
} else {
writeln("Hello, world!");
}
}

void main() {
hello(Color.yes, Traditional.yes); // this is wrong, but 
accepted

}
```


Why is Phobos `Flag` so overthought ?

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

I think this just works:

```d
enum Flag : bool
{
no,
yes
}

alias AllowVancancy = Flag; // example usage
```

Also this is completion friendly whereas Phobos version does not 
permit DCD completion as it's based on opDispatch.


Compare to phobos version:

```d
template Flag(string name) {
enum Flag : bool
{
no = false,
yes = true
}
}

struct Yes
{
template opDispatch(string name)
{
enum opDispatch = Flag!name.yes;
}
}

struct No
{
template opDispatch(string name)
{
enum opDispatch = Flag!name.no;
}
}
```

must be a reason but I cant find it RN ;)


Re: Phobos function to remove all occurances from dynamic array?

2024-05-06 Thread Lance Bachmeier via Digitalmars-d-learn
On Wednesday, 1 May 2024 at 15:18:03 UTC, Steven Schveighoffer 
wrote:
On Wednesday, 1 May 2024 at 01:09:33 UTC, Liam McGillivray 
wrote:
This is presumably such a common task that I'm surprised it 
isn't easy to find the answer by searching;


Is there a standard library function that removes all elements 
from a dynamic array that matches an input argument?


In `std.array` there's the `replace` function which is 
supposed to replace all occurrences that match an input with 
another. It seems to work as described on strings, but I get 
compiler errors when using it on other array types. I've tried 
using it to replace occurrences of a certain object in an 
array with `[]` in order to remove all occurrences, but it's 
not allowed.


Is there a Phobos function that does what I want? It would be 
crazy if there isn't.


`remove`

https://dlang.org/phobos/std_algorithm_mutation.html#remove

```d
arr = arr.remove!(v => shouldBeRemoved(v));
```

Why the reassignment? Because `remove` removes elements *in 
place*, and does not change the range extents. It returns the 
portion of the range that contains the unremoved elements.


So to give an example:

```d
auto arr = [1, 2, 3, 4, 5];
auto result = arr.remove!(i => i % 2 == 1); // remove odd 
elements

assert(result == [2, 4]);

// first 2 are the slice that is stored in result
// the last three are leftovers.
assert(arr == [2, 4, 3, 4, 5]);
```

-Steve


In case anyone comes upon this in a search, I wanted to point out 
a couple dangers of using remove. The first is that it mutates 
arr, as shown in Steve's example. The second is


```
result[0] = 4;
assert(result == [4, 4]);
assert(arr == [2, 4, 3, 4, 5]); // Fails
arr[0] = 2;
assert(result == [4, 4]); // Fails
```

Any future changes you make to result or arr change the other. 
You can use remove to avoid the allocation of a new array, but 
you better be sure you never read or modify the original array 
again. If you use filter


```
auto result = arr.filter!(i => i % 2 == 0).array;
```

arr is unchanged and you can use arr and result as you want.


Re: How can I put the current value of a variable into a delegate?

2024-05-06 Thread Steven Schveighoffer via Digitalmars-d-learn

On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote:
Delegates can be a pain, as they often have results different 
from what one would intuitively expect. This can easily result 
in bugs.


Here's a line that caused a bug that took me awhile to find:
```
foreach(card; unitCards) card.submitted = delegate() => 
selectUnit(card.unit);

```

Each `UnitInfoCard` object (which `card` is a member of) 
contains a `Unit` object called `unit`. The intention of this 
line was that each object in `unitCards` would call 
`selectUnit` with it's own `unit` every time it calls 
`submitted`. Instead, every card calls `submitted` with the 
*last* value of `card`.


Yes, this is because the foreach loop reuses the same memory slot 
for `card`.


Even though this is allocated as a closure, it still only 
allocates the frame stack of the *enclosing function*, and does 
not allocate a new slot for each loop iteration.


You can force this by using a lambda which allocates the closure:

```d
foreach(card; unitCards)
card.submitted = (c2) { return () => selectUnit(c2.unit); 
}(card);

```

This is a lambda which accepts `card` as a parameter, and returns 
an appropriate delegate. It is important to use a parameter, 
because if you just use card inside there, it's still using the 
single stack frame of the calling function!


I renamed the inner parameter `c2` to avoid confusion, but you 
could name it `card` also. Essentially, the stack frame of the 
inner function is now allocated a closure, and it has it's own 
reference to `card` as a parameter.


This is a very old issue: 
https://issues.dlang.org/show_bug.cgi?id=2043 since "moved" to 
https://issues.dlang.org/show_bug.cgi?id=23136


I would love to see a solution, but the workaround at least 
exists!


-Steve


Re: How can I put the current value of a variable into a delegate?

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

On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote:

Here's a line that caused a bug that took me awhile to find:
```
foreach(card; unitCards) card.submitted = delegate() => 
selectUnit(card.unit);

```


I think you can do:
```d
import std.algorithm.iteration : each;
unitCards.each!(c => c.submitted = () => selectUnit(c.unit));
```



Re: How can I put the current value of a variable into a delegate?

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

On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote:
This is because the delegate assignment causes the local `card` 
variable to remain alive. The delegate that's assigned is 
linked to this variable itself, not the value at the time that 
the delegate is assigned.


This is https://issues.dlang.org/show_bug.cgi?id=23136. Perhaps 
it can be fixed in the next edition.


Is there a way I can dereference a variable when placing it in 
a delegate, so that it's current value is used, rather than the 
variable itself?


I think you would need to make an array before the loop, assign 
to an indexed element and use that in the delegate.