HandleFromObject - HandleToObject ?

BlitzMax Forums/BlitzMax Programming/HandleFromObject - HandleToObject ?

ImaginaryHuman(Posted 2008) [#1]
I have an array of function pointers and I find the base address of the array memory and turn it into an Int Pointer. Then I can store integers in amongst the function pointers. How I use the contents of the array depends on how I interpret it, either calling a function or reading/writing integer values. This is working fine. But I also need to store references to custom types in the same array.

I have been looking at these two commands:

Function HandleFromObject( obj:Object )
Returns	An integer object handle
Description	Convert object to integer handle
Information	 After converting an object to an integer handle, you must later release it using the Release command.

Function HandleToObject:Object( handle )
Returns	The object associated with the integer handle
Description	Convert integer handle to object

I am unclear about how to use these (presuming this is the only way to make this work).

If I do MyIntArray[Offset]=HandleFromObject(MyCustomTypeInstance), this appears to store the type in the array once.

If I then do MyCustomType=MyCustomType(HandleToObject(MyIntArray[Offset])), this appears to retrieve the type from the array and change it back into MyCustomType.

However, I am confused by where it says that you have to call Release to release references, in order to keep the Garbage Collector happy. I won't necessarily be writing objects as many times as I read them - more likely they will be written infrequently and read frequently. When exactly do I need to be calling Release? When I *use*/convert the reference back to an object, or perhaps when I plan to delete the entire array? Also when I have converted an object to an integer, can't I store that integer anywhere I like any number of times and the garbage collector will have no idea about that or need to know that? I am just confused about the Release thing.


ImaginaryHuman(Posted 2008) [#2]
Anyone?


tonyg(Posted 2008) [#3]
As there are no other responses and you're looking for 'anyone'...
Aren't they simply in there for some bizarre compatability with B3D integer object system?
Personally, never had to use them as Mark (or was it Skid) said they were dreadfully slow and even he seemed guilty about putting them in.
<edit> Does this help? Maybe this ? or this
(I should never had searched.. I can't stop now and I can see you have contributed to half those posts)


plash(Posted 2008) [#4]
What's wrong with the code you posted Imaginary? Isn't it doing what your trying to do now? (cast to and from handle's and object's)

(For reference)
Local a:mytype=New mytype
Local b:Int=Int(a) 'convert to int handle

'Do whatever you want with the handle here

local a=VarPtr(b)[0] 'convert to object



Yan(Posted 2008) [#5]
All that happens when you create a handle is, a reference to the object is stored in a hash table and the key is returned. This means that a reference to that object will exist as long as the table entry remains, so it needs to be removed before the object can be collected. This is where release comes in.

When I *use*/convert the reference back to an object, or perhaps when I plan to delete the entire array?
When you plan to delete the array, or rather, when you no longer need the handle and it's safe for the object to be collected.

Also when I have converted an object to an integer, can I store that integer anywhere I like any number of times and the garbage collector will have no idea about that or need to know that?
Yes, the handle is just a plain old integer. Apart from taking care with handles to null objects, you only have to make sure that it's value, which can be held in *any* integer variable, isn't lost before you release it.


ImaginaryHuman(Posted 2008) [#6]
Plash, I found that when I tried to cast to a custom type other than a default blitzmax type, the compiler came up with an error saying it can't convert from an int to an <unknown>. So that's why I thought I needed to use the handle conversion commands. I will try the casting to an integer like you have done and see how that goes. Is your method really supposed to be able to work with casting custom types to integers and back?

Yan, thanks for the explaination, you perfectly articulated what I wanted to know about how that works. So I basically convert to an integer handle and store it somewhere, like in an array, and then I can use it any number of times I like - converting back from an int to an object basically looks in the hash table and finds the object, and then when I'm totally done with what I converted to an int handle, I Release it and then can collect the array.


Who was John Galt?(Posted 2008) [#7]
I can't remember the logic behind it now, but I remember reading up on them and thinking Max handles created more headaches than they solved. I never touch them.


plash(Posted 2008) [#8]
Is your method really supposed to be able to work with casting custom types to integers and back?
It's not my method! It's yours. From what I can see, if it works that is, it will only in non-strict/strict mode. Looks like *a* tries to assume what *b* points to, and automatically sets its type accordingly.

EDIT: Hey! kind of getting there..
Type mytype
	Field word:String
	
	Method Say()
		
		If word <> Null
			Print word
			
		Else
			Print "ERROR: No word set!"
			
		End If
		
	End Method
	
End Type

Local a:mytype = New mytype
	a.word = "hello!"
	
Local b:Byte Ptr = Varptr(a)
Print Int(Varptr(b)[0])

'Local obj:mytype = mytype(Varptr(b)[0])
'obj.Say()


All we really need to be able to do is this:
Local myobjpointer:mytype Ptr = VarPtr(a)

You could store it as an int using 'Local savedintptr:Int = Int(Varptr(myobjpointer)[0])', and maybe 'Local obj:mytype = mytype(savedintptr)' to cast it back.


plash(Posted 2008) [#9]
Woah! This is a weird feature:
Type GameObject
	
	Field msg:String

	Method Yell()
		Print msg
	End Method
	
	Method getSelf:GameObject()
		Return Self
	End Method

	Function getObj:GameObject(obj:GameObject)
		Return obj
	End Function
End Type

Local obj:GameObject = New GameObject
	obj.msg = "WIN!?!?!!"

Local idx:Int = obj.getSelf()    ' Turns object into a handle
Local b:Byte Ptr = Varptr(obj)
	Print idx
	Print Int(Varptr(b)[0]) 'Notice the difference in the printed values
	
Local obj2:GameObject = GameObject.getObj(idx) ' Turns handle into an object
obj2.Yell()

( http://www.blitzbasic.com/Community/posts.php?topic=41621#486966 )


plash(Posted 2008) [#10]
According to Brucey this should work:
Local a:mytype = New mytype
Local b:Byte Ptr = Varptr(a)

Local obj:mytype = mytype(HandleToObject(Int(b))) '< Brucey!
obj.Say()


But it doesn't :( ("Unhandled Memory Exception Error" - when it tries to call obj.Say(), because obj is Null)


fredborg(Posted 2008) [#11]
You only need to call Release once you remove the integer handle (generated by HandleFromObject) from the array.

HandleFromObject stores the object along with an integer handle in a map, and when you use HandleToObject it looks up the handle in the map and returns the object if it is present. Calling Release will remove the object + handle from the map.

Check the source code for blitz.mod/blitz_handle.c if you still don't understand how it works.

This is how HandleFrom/ToObject works:
Type MyType
	Method say()
		Print "*burp*"
	EndMethod
EndType
Local a:mytype = New mytype

'
' Convert object to integer handle
Local b:Int = HandleFromObject(a)

'
' Convert integer handle to object
Local obj:mytype = mytype(HandleToObject(b))
obj.Say()

'
' Remove from handle/object map
Release b



plash(Posted 2008) [#12]
I found something that works, but it probably does the same thing as the official functions (HandleFromObject and HandleToObject)
SuperStrict

Type mytype
	Field word:String
	
	Method Say()
		
		If word <> Null
			Print word
			
		Else
			Print "ERROR: No word set!"
			
		End If
		
	End Method
	
End Type

Local a:mytype = New mytype
	a.word = "hello!"
	
Local b:Byte Ptr = Varptr(a)
	Print Int(Varptr(b)[0])

Local iptr:Int = (Int Ptr Varptr a)[0] + 1 'HandleForObject(a)
	Print iptr

Local obj:mytype = mytype(ObjectForHandle(iptr)) 'mytype(HandleToObject(Int(b)))
If obj = Null Print "iadfgjaweg!"
obj.Say()


Function ObjectForHandle:Object(handle:Int)
  Local obj:Object

	(Int Ptr Varptr obj)[0] = handle - 1
	
	Return obj
	
End Function

Function HandleForObject:Int(obj:Object)
	
	Return (Int Ptr Varptr obj)[0] + 1
	
End Function

( http://www.blitzbasic.com/codearcs/codearcs.php?code=1876 )

You will also notice the code archive has functions for retaining and releasing handles, so no real progress here.. I wonder if you can even have a integer handle without having to 'release it'? - shouldn't have to release jack, considering its just a bloody integer.


ImaginaryHuman(Posted 2008) [#13]
Interesting code. Thanks guys.

BRL's method, which I looked at by going into the C file Blitz.c in the BRL.Blitz module, does some funky things, but basically uses a hash table like described above. I don't think you necessarily need a hash table as that's really just designed to store a bunch of handles in an efficient-to-find form which could just as easily be store somewhere else like in an array or a variable. BRL's method does incorporate garbage collection though.

I can follow your code to see that you're storing a `pointer to an object` somewhere and are just casting it back from the Object type. This seems simple enough.

I see in your function HandleForObject that you get into the address of the Object and then you return that address +1. Why the +1? Is that because someone said that the Fields of the object start at that address and you're anticipating using that address to access them? Otherwise why not just store Integer=Int Ptr(VarPtr(Obj))? Why do you read the content of the start of the Object and then add 1 to it?


plash(Posted 2008) [#14]
Why the +1? Is that because someone said that the Fields of the object start at that address and you're anticipating using that address to access them? Otherwise why not just store Integer=Int Ptr(VarPtr(Obj))? Why do you read the content of the start of the Object and then add 1 to it?
I have less a clue about any of this, as I mentioned, I simply copy-and-pasted the code bits.