Re: D doesn't have weak references. So how can I make a associative array of objects without preventing their destruction?
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?
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?
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?
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?
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?
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?