ID:1995892
 
Not Feasible
Applies to:DM Language
Status: Not Feasible

Implementing this feature is not possible now or in the foreseeable future
It would be wonderful if we could have a refcount(var/datum/D) proc, used primarily for debugging, which would (similarly to how del() finds all the references) return an associative list in the form of something like

"[some sort of datum identifier]" = "[name of var referencing D]"


This way, when we're trying to garbage collect, if for some reason we miss something somewhere and we've got a memory leak, we can use this to pinpoint what we're missing.
+
+
One of the difficulties with this kind of thing is that the act of including the datum in a proc call will itself create a new reference. Take for example this code:

proc/MyProc()
var/datum/D = new
// At this point, there is probably only one ref.
// It is unlikely that D has been loaded into internal vars.
. = refcount(D)
// When refcount(D) is called, D is being loaded into internal var v1, pushed to the stack, and popped again.
// Its refcount therefore will probably read as 2.

Any manipulation of a value has a chance to temporarily increase its refcount. As a result, a refcount() call might not actually be useful. The only way this would work out would be if the current proc's temporary references are properly accounted for.
In response to Lummox JR
Lummox JR wrote:
One of the difficulties with this kind of thing is that the act of including the datum in a proc call will itself create a new reference. Take for example this code:

proc/MyProc()
> var/datum/D = new
> // At this point, there is probably only one ref.
> // It is unlikely that D has been loaded into internal vars.
> . = refcount(D)
> // When refcount(D) is called, D is being loaded into internal var v1, pushed to the stack, and popped again.
> // Its refcount therefore will probably read as 2.

Any manipulation of a value has a chance to temporarily increase its refcount. As a result, a refcount() call might not actually be useful. The only way this would work out would be if the current proc's temporary references are properly accounted for.

What about giving datum a read-only refcount var that contains the number of references to that particular datum? I'm not sure how easy/difficult this would be, but it would be somewhat worth a shot... right?
In response to Lummox JR
Lummox JR wrote:
As a result, a refcount() call might not actually be useful. The only way this would work out would be if the current proc's temporary references are properly accounted for.

Understood, but you could just remove that from the returned list. Since refcount() should(?) return fairly quickly the reference shouldn't stay long enough to be a problem, plus this should only really be used for debugging when you know there's a loose reference, and removed once you've cleared it up.
In response to Pokemonred200
Pokemonred200 wrote:
What about giving datum a read-only refcount var that contains the number of references to that particular datum? I'm not sure how easy/difficult this would be, but it would be somewhat worth a shot... right?

That's the exact same issue. Temporary refs will still end up appearing in the proc.
In response to Rushnut
Rushnut wrote:
Understood, but you could just remove that from the returned list.

List? It's a count and nothing more.

And complicating this is that some types are not refcounted, and among the ones that are, some of them (like strings) contain permanent members that are not.
In response to Lummox JR
Lummox JR wrote:
Pokemonred200 wrote:
What about giving datum a read-only refcount var that contains the number of references to that particular datum? I'm not sure how easy/difficult this would be, but it would be somewhat worth a shot... right?

That's the exact same issue. Temporary refs will still end up appearing in the proc.

Oh. I thought it would've been like std::shared_ptr's use_count() in C++, in that doing this

mob/proc/thing()
var datum/D = new
world << "[D.refcount]" // Outputs '1', as D probably hasn't been assigned to anything else yet
var datum/D2 = D
world << "[D2.refcount]" // Outputs '2'
D = null
world << "[D2.refcount]" // Outputs '1'


world work properly, much like

int main(){
std::shared_ptr<int> in = std::make_shared<int>(5);
std::cout << in.use_count() << '\n'; // Outputs '1'
std::shared_ptr<int> in2 = in;
std::cout << in2.use_count() << '\n'; // Outputs '2'
in = nullptr;
std::cout << in2.use_count() << '\n'; // Outputs '1'
}


would work in C++11.
In response to Lummox JR
That's not what my request was? The Del proc seems to be able to find references easily enough. Whilst having a numerical value for the number of references, being able to have it return a list (Like my request said) that contains some identifier (if possible) of what the reference is tied to and the name of the variable acting as a reference (...like my request said).

Just a number = Handy
A list with actual information we can more easily use = A godsend.


Maybe I used the term refcount a little wrong. Perhaps reflist()? refcount() itself could also exist but would be redundant if reflist() existed.
In response to Rushnut
Rushnut wrote:
That's not what my request was? The Del proc seems to be able to find references easily enough. Whilst having a numerical value for the number of references, being able to have it return a list (Like my request said) that contains some identifier (if possible) of what the reference is tied to and the name of the variable acting as a reference (...like my request said).

An exhaustive list of what the refs actually are isn't any kind of practical. This would murder server performance. I didn't realize that was the actual request, since you called it refcount(). Something like reflist() is simply not feasible.
Lummox JR resolved issue (Not Feasible)
Then how does Del() do it?

Even if it is intensive, it's not supposed to be actively used in a game, rather simply as a debugging tool for polishing. It'll help track down issues with your game and make it run smoother, even if it is intensive to use, it isn't meant to be left in.
There is a scanning process. In theory that scanning process could be adapted to be used for some other things, but the routines involved do not keep track of any information about where the reference is. Pretty much all they're for is to clear the value if necessary, or in some cases count it.

In other words, I can traverse the refs, but the traversal doesn't keep track of where it actually is. It would have no way of sending information back that says "Hey, I found a ref in obj #123's 'something' var."