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

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

On Friday, 10 May 2024 at 13:27:40 UTC, Dukc wrote:

Steven Schveighoffer kirjoitti 10.5.2024 klo 16.01:

On Friday, 10 May 2024 at 11:05:28 UTC, Dukc wrote:
This also gets inferred as `pure` - meaning that if you use 
it twice for the same `WeakRef`, the compiler may reuse the 
result of the first dereference for the second call, without 
checking whether the referred value has changed!


This would be weak pure since the reference is mutable. This 
cannot be memoized.


The difference is the type. With a pointer parameter (both a 
bare one and one in a struct), the compiler can cache the 
result only when the pointed data is similar. However, here we 
have an integer parameter. It can be cached if it itself is 
similar to the one in the other function call. The compiler 
doesn't have to know, nor can know, when a `size_t` is a 
pointer in disguise.


This why I would just use ref counting if I were the topic 
author, trying to be smart will often comes back when one doesn't 
expect.


And as stated by previous author if the goal is to have 
self-clearable weak reference it will need some infrastructure 
anyway, so tbh this will greatly outweight any possible benefits 
of having weak refs.


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

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

Steven Schveighoffer kirjoitti 10.5.2024 klo 16.01:

On Friday, 10 May 2024 at 11:05:28 UTC, Dukc wrote:
This also gets inferred as `pure` - meaning that if you use it twice 
for the same `WeakRef`, the compiler may reuse the result of the first 
dereference for the second call, without checking whether the referred 
value has changed!


This would be weak pure since the reference is mutable. This cannot be 
memoized.


The difference is the type. With a pointer parameter (both a bare one 
and one in a struct), the compiler can cache the result only when the 
pointed data is similar. However, here we have an integer parameter. It 
can be cached if it itself is similar to the one in the other function 
call. The compiler doesn't have to know, nor can know, when a `size_t` 
is a pointer in disguise.


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

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

On Friday, 10 May 2024 at 11:05:28 UTC, Dukc wrote:



This also gets inferred as `pure` - meaning that if you use it 
twice for the same `WeakRef`, the compiler may reuse the result 
of the first dereference for the second call, without checking 
whether the referred value has changed!


This would be weak pure since the reference is mutable. This 
cannot be memoized.


-Steve


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

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

evilrat kirjoitti 9.5.2024 klo 18.19:

```d
struct WeakRef(T) {
     private size_t _handle; // same size as a pointer

     this(T* ptr) {
     _handle = cast(size_t) ptr;
     }

     T* getRef() {
     return cast(T*) _handle;
     }

     // do the rest ...
}
```

[1] https://code.dlang.org/packages/automem


There is a hidden danger with using this struct. Since `getRef` is a 
template, it will be inferred as `pure`. Now, consider a function using it:


```D
auto derefer(WeakrefT)(WeakrefT wr) => *wr.getRef;
```

This also gets inferred as `pure` - meaning that if you use it twice for 
the same `WeakRef`, the compiler may reuse the result of the first 
dereference for the second call, without checking whether the referred 
value has changed!


You probably should add some never-executed dummy operation to `getRef` 
that prevents it from becoming `pure` if you go with this design.


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

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

On Thursday, 9 May 2024 at 00:39:49 UTC, Liam McGillivray wrote:


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


There is libraries like `automem`[1] that implements refcounting 
and more.
Without showing your code for ref counted struct we can't help 
you.


As for weak references, maybe you could "trick" the GC by using 
the fact that simple types are not scanned, i.e. do something 
like this but I have no idea if this is going to work at all, 
alternatively you can also try using `ubyte[size_t.sizeof]`.


Keep in mind that classes is already references so you don't need 
that extra pointer for classes, can be versioned with template 
specialization.


```d
struct WeakRef(T) {
private size_t _handle; // same size as a pointer

this(T* ptr) {
_handle = cast(size_t) ptr;
}

T* getRef() {
return cast(T*) _handle;
}

// do the rest ...
}
```

[1] https://code.dlang.org/packages/automem


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?