Help with reflections

BlitzMax Forums/BlitzMax Beginners Area/Help with reflections

Leo Santos(Posted 2008) [#1]
Hi Everybody,

I'm trying to write a function that goes through every object in a scene and saves its state (basically, it will be a project file for a game editor). Since I don't want to hard-code which fields get saved according to which kind of entity, I decided to learn to new reflection features.

It works well for simple fields (int, float, string...) but I'm having trouble when the object contains a field that asks another type, like this:



The big problem is: if I run into a field that contains a different type (in this example, a "TShape" object) how do I:

1 - Identify that type?
2 - Identify a specific field within that type? In my example, If I could extract the "name" field from the shape I could easily reconnect the two objects when I load the project file in the editor.

Any help is appreciated! My brain is kinda numb right now...

Cheers,
Leo.


DavidDC(Posted 2008) [#2]
Why not check Brucey's Bah.Persistence mod?


Leo Santos(Posted 2008) [#3]
Thank you, the serializer mod looks great!

But... I fell that I'm already close to getting it working, and that I would learn more if solved that little problem. So far, I made everything in my framework from scratch, and learned a ton from doing so! So all that I really need is...how do I identify/access the type that's in a field?

Thanks!


DavidDC(Posted 2008) [#4]
The general approach is via recursion. You handle all the base types (int, string etc), then if you've got an object type left, recurse.

I mentioned Brucey's mod as the code is all there - and it's one of the few recursive Reflection code samples I've seen that properly handles circular references.

TTypeId has a Name() method. Some snippets:
Local object_id:TTypeId=TTypeId.ForObject(_object:Object)

'	Type name - float, int, string etc	
Local s_name:String = object_id.Name() 

If object_id.ExtendsType(ArrayTypeId) Then...
If object_id.ExtendsType(TTypeId.ForName("TList")) Then...




Leo Santos(Posted 2008) [#5]
I tried downloading BAH.Persistence to take a look at the code, but can't find it... It's not on Brucey's page, or on the GoogleCode project page (there's no link on that one). Where can I find it?


DavidDC(Posted 2008) [#6]
http://maxmods.googlecode.com/svn/trunk/


Emmett(Posted 2008) [#7]
post deleted - was same as David.


tin(Posted 2008) [#8]
BTW. what is reflection?


plash(Posted 2008) [#9]
http://en.wikipedia.org/wiki/Reflection_%28computer_science%29
basically its just a way for a program to do stuff with its own code (functions, types and methods etc) at runtime, so from user interaction along side a scripting language etc.


Volker(Posted 2008) [#10]
I started with the code from Mark:
Type TObjectStream

	Method ReadObject:Object()
		'read type name
		Local name$=_stream.ReadLine()
		
		'find type
		Local id:TTypeId=TTypeId.ForName( name )
		
		'create new object!
		Local obj:Object=id.NewObject()
		
		'restore it's fields...
		For Local fld:TField=EachIn id.EnumFields()

			'ignore non-serializable fields
			If Not fld.MetaData( "serializable" ) Continue
			
			'get type of field
			Local fldType:TTypeId=fld.TypeId()
			
			'is field an object or int/float etc?
			If fldType.ExtendsType( ObjectTypeId )
				'field is an object - recurse
				fld.Set obj,ReadObject()
			Else
				'field must be int/float etc...a 'leaf'
				fld.Set obj,_stream.ReadLine()
			EndIf
		Next

		Return obj
	End Method
	
	Method WriteObject( obj:Object )
		'what type of object is it?
		Local id:TTypeId=TTypeId.ForObject( obj )
		
		'write it's type name, eg: "TMyType"
		_stream.WriteLine id.Name()
		
		'scan it's fields...
		For Local fld:TField=EachIn id.EnumFields()

			'ignore non-serializable fields
			If Not fld.MetaData( "serializable" ) Continue
			
			'get type of field
			Local fldType:TTypeId=fld.TypeId()
			
			'is field an object or int/float etc?
			If fldType.ExtendsType( ObjectTypeId )
				'field is an object - recurse
				WriteObject fld.Get( obj )
			Else
				'field must be int/float etc...a 'leaf'
				_stream.WriteLine fld.Get( obj ).ToString()
			EndIf
		Next
	End Method
	
	Field _stream:TStream 'underlying stream
	
End Type



Leo Santos(Posted 2008) [#11]
Thanks for the help and the code (and for making it so easy to read!). I'm putting it to good use right now.

And Tin, another way of explaining reflection is: it's a feature that allows you to identify all the fields and methods inside an object. You can, for instance, expose the fields of an object that is selected by the user (some programs call that kind of view an "inspector" or "explorer"), etc.

I don't blame you for not knowing it: the documentation in Bmax seems to explain it for people who already know what it does... :-P ...like many other things...those docs need a major overhaul for beginners (specially considering that Bmax is kinda marketed as "easy for beginners").

And where's the Wiki?!?!?

Cheers!
Leo.