ID:1240233
 
(See the best response by Kozuma3.)
Is there a way to tell who called what in order to prevent improper usage of a function???


garbage_friendly
Del()
if(was not called by garbage collector)
return
..()
Best response
If it's for the garbage collector couldn't you check if it was located anywhere or its current location?
In response to Kozuma3
Kozuma3 wrote:
If it's for the garbage collector couldn't you check if it was located anywhere or its current location?

Hmm, yeah... the loc WOULD be null if the garbage collector was calling Del... wouldn't it?
I believe the garbage collector deletes things not located anywhere or referenced anywhere. Such as in a list.
the loc being null does not explicitly mean the object is being garbage collected.

You can have objects with no loc, but be in a list, or be referenced in a variable.

Mobs can also have no loc, but the client still has references to them.
In my situation, this is working best:

whatever
Del()
if(!loc) ..()
else
loc = null
//set any other references to null
In response to Super Saiyan X
Super Saiyan X wrote:
the loc being null does not explicitly mean the object is being garbage collected.

You can have objects with no loc, but be in a list, or be referenced in a variable.

Mobs can also have no loc, but the client still has references to them.

Yeah, of course. Making sure you clear refs is your responsibility. I just wanted to make Del() bullet proof.
In response to Super Saiyan X
Super Saiyan X wrote:
the loc being null does not explicitly mean the object is being garbage collected.
You can have objects with no loc, but be in a list, or be referenced in a variable.

I said this just with less detail :P

Mobs can also have no loc, but the client still has references to them.

Which answers itself.

In response to Kozuma3
Point being, the object won't be garbage collected in those cases even with no loc. So checking for no loc is not enough to say "this object was garbage collected," and setting loc = null does not always cause garbage collection.
In response to Kaiochao
Kaiochao wrote:
Point being, the object won't be garbage collected in those cases even with no loc. So checking for no loc is not enough to say "this object was garbage collected," and setting loc = null does not always cause garbage collection.

Which is why if it's in a list or referenced anywhere it won't work, yes I've stated this in a less detailed way as I know Fireking knows what it does himself.
Aren't objects garbage collected if they have all of their variables set to null?
If nothing is referencing them and they have a null loc I believe.
In response to Kozuma3
Kozuma3 wrote:
they have a null loc

Albro1 wrote:
all of their variables set to null?

XD

In response to Albro1
Albro1 wrote:
Aren't objects garbage collected if they have all of their variables set to null?

Yes. Well technically no, you need to null out any references to the object. The garbage collector calls Del() when it is ready to destroy the object. The programmer can also call Del(). You can have an object that has all sorts of variables set, but if any existing thing in the world has a variable equal to the reference of the object you wish to delete, the garbage collector will leave it alone.

There's no exact way to tell if Del() is being called by the garbage collector, but one quick way is to check if loc is null. It is possible for the datum you're dealing with to still exist (and be ignored by the garbage collector) with a null loc, so its up to you to check other variables before betting on the garbage collector case. In my situation, it was safe to do this assumption, hence my question being answered.

For anyone else out there that is unsure of what we're talking about, I'll explain a bit.

A lot of new commers and beginner programmers will delete a datum (obj, mob, turf, atom, whatever) when they don't need it anymore...

potion
proc/Use()
usr.hp += 10
del src


This is normally ok, but you'll have these same people assuming, "Well, this is how you delete something". But that's not always a safe assumption. If you're dealing with hundreds, thousands, or tens of thousands of objects, and they all need to delete at the same time... well you're going to run into a very very long frame in the cycle, which is going to cause freezing on the server, and subsequently to all the clients.

particle
proc/life()
if(too far from father)
del src // this is bad!


Above we see a particle can delete its self when its too far away from its owner... Problem is, if we used that particle to build a burst effect, all of the outer edges will need to be destroyed at the same time, and this would cause a "hiccup"

How can we work around this limitation? Garbage collector.

The garbage collector is something that works for you, automatically, always in the background. It takes a look at existing atoms / datums in the world and when they have 0 references (tracked by a hidden secret internal reference counter) it removes them from memory. You can trigger this to happen by ... removing all of the references! and you do that by setting them to null! Best thing about this method is that the garbage collector will never attempt to remove more than 1 thing per frame. So the removal of all those built up items happens over time. This is the behavior you want because that processing power is spread out over a period of time instead of spending all the power on removing all those items in a single frame...

particle
proc/life()
if(too far from dad)
loc = null
owner = null
//garbage collector will figure this out in a minute and remove the particle on its own


You will need to debug this. You are bound to leave behind a reference, and its up to you to track them all down and handle them all, specifically. If the particle gets into an inventory or something, or added to a list... it will stick around and the garbage collector will leave it alone...

You can help your self keep track of this by relying on one or two variables to be null when its time to collect. If you have that information to lean on, then you can do this:

particle
Del()
if(!loc && !owner) // we know by this, its really time to die!
..()//allow the delete!
else //we called del src somewhere
loc = null
owner = null
//we don't take default action here, we want the garbage collector to do it


As you see above, we can still use del particle when we want, without disturbing the garbage collection system and wasting time in our frame.

burst_effect
New(loc)
for(var/i = 1 to 1000)
new particle(loc, src)
particle
var/owner = null
New(loc, owner)
src.owner = owner
walk_away(src, loc)
Move()
if(get_dist(src, owner) >= 10)
del src
Del()
if(!owner && !loc) ..()
else
owner = null
loc = null


In the example you'll see that we call del src which does indeed call particle.Del() but the actual deletion does not happen while the particle exists on the map. Instead, we null out the references and wait for the garbage collector to handle it which is the proper way and most efficient way to do it.
In response to Albro1
Albro1 wrote:
Aren't objects garbage collected if they have all of their variables set to null?

It's... not possible to set all of an object's variables to null.
In response to FIREking
The significant part of setting an object's loc to null isn't that the object's loc variable is null, but that the loc atom no longer contains the object; a side effect due to how the movement system works (symmetry).
In response to Kaiochao
Kaiochao wrote:
The significant part of setting an object's loc to null isn't that the object's loc variable is null, but that the loc atom no longer contains the object; a side effect due to how the movement system works.

Yes! Let that ring true in this post!

Garbage collector kills an object not when its variables are null, but when nothing else references that object! Kind of the opposite of what Albro1 said.
In response to FIREking
FIREking wrote:
In my situation, this is working best:

> whatever
> Del()
> if(!loc) ..()
> else
> loc = null
> //set any other references to null
>


It's not guaranteed, sure.

var/atom/A = new()
A.loc = null
del(A) // Ho ho


The inverse does guarantee the garbage collector /didn't/ call the delete, which for your purposes, seems to be good enough?

The other more manual strategy would be a code-search for del() and inspecting each of them, to see if that's the kind of forced delete you want to be doing. The cases where you /need/ to make a del() call I think are quite rare, and I'd adopt the convention probably of using del() sparingly and taking proper care of your references.

If nothing else, the code walk is a good way to review your code for design/performance issues.

In response to Stephen001
Stephen001 wrote:
FIREking wrote:
In my situation, this is working best:

> > whatever
> > Del()
> > if(!loc) ..()
> > else
> > loc = null
> > //set any other references to null
> >

It's not guaranteed, sure.

> var/atom/A = new()
> A.loc = null
> del(A) // Ho ho
>

The inverse does guarantee the garbage collector /didn't/ call the delete, which for your purposes, seems to be good enough?

The other more manual strategy would be a code-search for del() and inspecting each of them, to see if that's the kind of forced delete you want to be doing. The cases where you /need/ to make a del() call I think are quite rare, and I'd adopt the convention probably of using del() sparingly and taking proper care of your references.

If nothing else, the code walk is a good way to review your code for design/performance issues.

Yeah, but every time you wanted to delete something, and lets say there were a lot of references to worry about, wouldn't you have too many lines of code that would need to be copy and pasted in multiple places? That's why you put that code in the Del() proc and delegate there.
I'd be inclined to ask "What kind of good design has too many references to manage?". I'm sure you know, Fireking, but for the benefit of the reader, you'd like to keep coupling low in projects to make things easier to maintain, testable and of course ... easier to let garbage collection do it's thing.

Wiki:Coupling_(computer_programming)

I'd agree though, for code you're inheriting or a belt and braces thing where you think libraries might be hard deleting, this kind of addition is nice. I'd say it's a work-around, though, but definitely better than nothing.
Page: 1 2