Can an object delete itself?

BlitzMax Forums/BlitzMax Programming/Can an object delete itself?

GfK(Posted 2014) [#1]
Either I'm having an epic brainfart, or... actually, no, I'm just having an epic brainfart.

I wanted to put a "reset" method in my class, which basically (at the moment) just deletes that instance of the object (it will do other stuff beforehand, later, hence why I wanted it in a method). I thought this code would be the way, but apparently not:
Local a:myType = New myType

a.x = 100

a.reset

Print a.x    'the aim is to get a "attempt to access field or method of Null object" error here

Type myType
	Field x:Int
	
	Method reset()
		Self = Null 'but instead, I get "expression must be a variable" here
	End Method	
End Type



Yasha(Posted 2014) [#2]
Even if you could assign to Self in that way, while it might break the implementation of the instance, how can that method see the reference from a and "unhook" that? If a is in scope, the object is still in use, regardless of what the reset method has to say about it.

This is a great illustration of the importance of trusting the GC... The best-case scenario (if it were to let you do this) is you create an invalid reference in code that ought to still be able to use a live object.

If you design your code in such a fashion that you can prove extra refs like a don't exist (perhaps by making sure such objects are locally-created or copies), you can add manual calls to the cleanup method (reset without the Null part), at the end of the scope where the single-reference was in use; if you can't prove this, you shouldn't be trying to manually dictate when cleanup happens because strictly speaking you don't actually know that cleanup should happen (otherwise there is no point in the ref at a existing at all).

Alternatively, if you specifically need cleanup to be aggressive, perhaps using the aggressive GC mode and manually forced calls to GCCollect would be the best way forward, and put finalisation code in Delete as usual. Hopefully that should result in things getting finalised as soon as they go out of scope.


GfK(Posted 2014) [#3]
I just wanted there to be some hidden witchcraft that makes it easy/tidy. Expecting a little too much today.


Yasha(Posted 2014) [#4]
That may well still be an option:

-- firstly, if the leaked reference thing isn't integral to the design and all you need is fast cleanup, as above, a more aggressive GC mode might be the way forward

-- if you do want to be able to "remotely kill" references outside the current scope, you could always pass your instances of myTypeReal around in a myType 'wrapper' whose "real object" field can be nulled (so you get the Null Object Exception when a tries to dereference a.real.x; a still holds a small and meaningless wrapper object, but has been cut off from any actual content because myType.reset now nulls the .real field)

-- you could wrap scopes in something along the lines of a 'selfContainer' function, that creates instances from templates, passes them to the wrapped procedure to 'do' stuff, and then cleans up the instances before returning so that none of the objects in question actually escape the body of the procedure where you use them (basically something along the lines of CL's 'Unwind-Protect' or C#'s 'using')


Who was John Galt?(Posted 2014) [#5]
Yup, it can be done but requires the instance to have some knowledge about how it's referenced.

I usually have a type global list that contains all instances of the object. Your object could remove itself from the list, then assuming there are no other references, *POOF* on the next GC run.

In your example, the instance could be passed a pointer to the variable 'a' on creation, and null 'a' via that.

--There are usually better ways of doing things, though--

I believe there is a method that is called just prior to object destruction that you can put cleanup code into. I forget the name, but maybe that is all you need? Only caveat is that you can't guarantee exactly when it gets called- GC decides that.


Kryzon(Posted 2014) [#6]
If you don't mind a procedural way:
Type myType

	Field x:Int

End Type


Function Free( instance:Object Var )

	instance = Null

End Function

'------------------------------------------

Local a:myType = New myType

a.x = 100

Free( a )

Print a.x 
But it does not give an error.