Re: Why is Phobos `Flag` so overthought ?

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

On Wednesday, 8 May 2024 at 04:27:13 UTC, cc wrote:
It doesn't allow a simple boolean to be used as an argument, or 
any other Flag as they are different instantiations of a 
template rather than equivalent aliases.
It is however awful, cumbersome, annoying design and needs to 
be completely phased out now that we have named arguments.


Flag enforces that the argument says what it relates to. `true` 
does not say what it relates to. Named arguments are optional, so 
I don't see how they could make Flag redundant.


Re: Why is Phobos `Flag` so overthought ?

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

Nick Treleaven kirjoitti 8.5.2024 klo 13.24:

On Wednesday, 8 May 2024 at 04:27:13 UTC, cc wrote:
It doesn't allow a simple boolean to be used as an argument, or any 
other Flag as they are different instantiations of a template rather 
than equivalent aliases.
It is however awful, cumbersome, annoying design and needs to be 
completely phased out now that we have named arguments.


Flag enforces that the argument says what it relates to. `true` does not 
say what it relates to. Named arguments are optional, so I don't see how 
they could make Flag redundant.


Well,

```D
private struct Undefinable{}

auto functionTakingFlags
(   int normalArg,
Undefinable = Undefinable.init,
bool Flag1,
Undefinable = Undefinable.init,
bool Flag2
){  // fun body...
}
```

As I understand it, this forces the client to use named arguments 
because they would be trying to pass an `Undefinable` otherwise. They 
probably could pass `Undefinable` if they really wanted and therefore 
avoid using named args but they wouldn't do that accidentally.


Whether that is any better than the library `Flag` type is up to taste.


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

2024-05-08 Thread Rene Zwanenburg via Digitalmars-d-learn

On Monday, 6 May 2024 at 16:41:38 UTC, Steven Schveighoffer wrote:
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


Interestingly enough C# used to have the same behaviour but MS 
decided to go for a breaking change in C# 5; now it behaves as 
most people expect.


Since it's an unsolved problem to keep links working for 10+ 
years I gave up looking for something official about the subject. 
Here's an SO question about it though:


https://stackoverflow.com/questions/14184515/action-delegate-uses-the-last-values-of-variables-declared-outside-foreach-loop




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

2024-05-08 Thread Liam McGillivray via Digitalmars-d-learn

On Monday, 6 May 2024 at 16:41:38 UTC, Steven Schveighoffer wrote:

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 would love to see a solution, but the workaround at least 
exists!


-Steve


Well that's something. It's not a very good solution for a 
language that aims for readability. It took me awhile looking at 
it to figure out what it is about, as I'm not familiar with this 
syntax.


The solution that I did before seeing this was to add a function 
to `UnitInfoCard` to give it a delegate with a `Unit unit` 
parameter, and then that function would give that function with 
the `unit` parameter set to itself to it's own `submitted` 
member. I will probably keep it like this for readability.


```
void clickAction(void delegate(Unit) @safe clickAction) {
submitted = () => clickAction(unit);
}
```


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

2024-05-08 Thread Liam McGillivray via Digitalmars-d-learn

On Wednesday, 8 May 2024 at 12:29:05 UTC, Rene Zwanenburg wrote:
Interestingly enough C# used to have the same behaviour but MS 
decided to go for a breaking change in C# 5; now it behaves as 
most people expect.


Wow! I wonder if D would be willing to allow such a breaking 
change with the release of Phobos 3. My choice would be to have 
it use the current value by default for value types, but allow 
them to be linked to the same memory address using `*&` when the 
variable is placed in a delegate. I think that the distinction 
between value types and reference types should be consistent.


If such a breaking change isn't considered acceptable, I suppose 
a new operator can be introduced for dereferencing a variable 
when placed in a delegate. Maybe `#` or `$` if they don't 
conflict with any existing use of those symbols.


D doesn't have weak references. So how can I make a associative array of objects without preventing their destruction?

2024-05-08 Thread Liam McGillivray via Digitalmars-d-learn
A "weak reference" (in the sense that I'm referring to) is a 
feature in some programming languages for a reference to an 
object that doesn't prevent the GC from destroying that object.


My current understanding is that D doesn't have weak references, 
though I've found some posts in this forum from many years back 
that mention something called "weakref". So is weakref a real 
thing, or just a concept that never got implemented?


The functionality that I'm going to describe would be easy with 
weak references, but I don't know how I would implement it 
without it. If there is a way to implement it without it, I would 
like to know how. I am going to describe my specific example, but 
it may apply to any class that's initialized using contents of a 
file without any of that data being modified after.


In my particular case, the class I've created is a wrapper for 
the `Texture2D` struct in Raylib. This class holds an image that 
was loaded from a file.


```
Sprite[string] spritesByPath;

Sprite getSprite(string path) {
path = path.asAbsolutePath;

if (path !in spritesByPath) {
spritesByPath[path] = new Sprite(path);
}

return spritesByPath[path];
}

class Sprite
{
Texture2D texture;
alias this = texture;
string path;

this(string path) {
texture = LoadTexture(path.toStringz);
this.path = path;
}

~this() {
if (IsWindowReady) UnloadTexture(texture);
if (path in spritesByPath) spritesByName.remove(path);
}
}
```

Alternatively, `spritesByPath` and `getSprite` may be static 
members of `Sprite`.


If D had weak references, than `spritesByPath` would be made of 
weak references so that they don't prevent the destruction of 
`Sprite` objects, which should be destroyed whenever they don't 
have any references elsewhere.


I've considered making `Sprite` reference-counted, but I couldn't 
manage to figure out how to do it properly. I tried doing 
`SafeRefCounted!Sprite` but the compiler said it doesn't work on 
`Object` types. I then tried making my own struct for reference 
counting that would be placed in place of a direct reference to 
the `Sprite` object, but there was some bug in which sometimes it 
didn't increment the reference count, so it didn't work.


What's a good way I can achieve what I'm trying to do, using 
either reference counting or a garbage-collected object?