Passing Types to functions

BlitzMax Forums/BlitzMax Beginners Area/Passing Types to functions

spacerat(Posted 2007) [#1]
Hello again for the second time in under 12 hours!
So this has been bothering me for a while, how do you pass an actual type (not an instance of the type) to a function?

For example, I want to do this:
Type TBall
        Method New()
                Objects.Addlast(self)
        EndMethod
EndType
Type TDrWatson
        Method New()
                Objects.Addlast(self)
        EndMethod
EndType

Function ObjectCount:Int(Obj:Type) 
	Local num:Int
	For Local o:Obj = EachIn Objects
		num:+1
	Next
	Return num
End Function

Global Objects:TList=new TList
new TBall
new TBall
new TDrWatson

print ObjectCount(TBall)
print ObjectCount(TDrWatson)


However I simply get told "Compile Error: Expecting identifier but encountered Type". This leads me to think that maybe the solution lies in pointers.

There are other things this would be useful for, for instance functions which can create generic objects depending on which object is passed, etc.

I do kind of have a solution in mind for if this isn't possible, that is to assign each type a Const ID thing, and just check for that. However that would be a lot clumsier, and I'd prefer not to have to.


SebHoll(Posted 2007) [#2]
In essence, I'm not sure you can, although there might be a way using reflection. However, I thought it might be worth mentioning a few points about your code.

1. When a new type instance is created, the New() method is run for the new type instance. Remember, a BlitzMax function doesn't have a type instance associated with it - you can call functions without a specific instance, for example...

TBall.myFunction()
You wouldn't be able to do that with a method. You'd have to make a new ball, and then call the method with it.

Local tmpBall:TBall = New TBall
tmpBall.myMethod()
2. I see what you are trying to do but I'm not entirely sure it can be done that way, unless you start using reflection. Instead, you may want to add functions to each type to count how many of its own type it can find.

3. Finally, I think it's bad practice to put parentheses "()" after your end keywords. You don't need them.

How about something like this:

Global lstObjects:TList = New TList

Type TBall
	Method New()	'The New() you are attempting to use, is actually a method.
		lstObjects.Addlast(Self)
	EndMethod
	Function CountInList( pList:TList )
		Local i%
		For Local tmpBall:TBall = EachIn pList
			i:+1
		Next
		Return i
	EndFunction
EndType

Type TDrWatson
	Method New()
		lstObjects.Addlast(Self)
	EndMethod
	Function CountInList( pList:TList )
		Local i%
		For Local tmpDrWatson:TDrWatson = EachIn pList
			i:+1
		Next
		Return i
	EndFunction
EndType

New TBall
New TBall
New TDrWatson

Print "Total No. of Objects: "+ lstObjects.Count()	
Print "No. of Balls: " + TBall.CountInList( lstObjects )
Print "No. of Dr Watsons: " + TDrWatson.CountInList( lstObjects )
Hope this helps! :-)


spacerat(Posted 2007) [#3]
Arrrrghhhhh, I knew new is a method, I can't believe I typed function, and same for putting ()s on the end of ends! (and I have fixed my code example accordingly)

As for your example, that might be just what I was looking for. The thing is, what I'm trying to do here isn't quite as simple as what I asked, because all of my objects are extending a base object. I tried my ID method just now using Globals in the types, but it kept referring to the ID assigned to the base type.

I shall proceed to test your solution in the context of my program, and edit when I see if it works.


Sledge(Posted 2007) [#4]
3. Finally, I think it's bad practice to put parentheses "()" after your end keywords. You don't need them.

Parenthesis make it clear that you're referencing a function/method rather than a global/field. Things looking like what they are = good practise, surely?


spacerat(Posted 2007) [#5]
@Sledge, things break if you stick parentheses after end... (wait were you agreeing or disagreeing?)


I realised that for your technique SebHoll, you need to have that function in every type, and since I'm trying to make a game framework which avoids having to do repetitive things like that, it's not an option (even though it's a cool idea). So I settled on something like this:
Global Objects:TList=New TList
Type TObject
	Field id$
	Method New()
		Objects.addlast(Self)
	EndMethod
	''' etc etc game framework stuff goes here
EndType

Type TBall Extends TObject
	Method New()
		id="Ball"
	EndMethod
EndType
Type TLulz Extends TObject
	Method New()
		id="Lulz"
	EndMethod
EndType

Function CheckInList%(name$,list:TList)
	Local num%=0
	For Local c:TObject=EachIn list
		If name="" Or name=c.id num:+1
	Next
	Return num
EndFunction

New TLulz
New TLulz
New TBall

Print CheckInList("Ball",Objects)
Print CheckInList("Lulz",Objects)


That might solve the particular problem, but it still leaves me wondering if it _is_ possible to reference to Types like I mentioned. I mean, you can refer to functions and methods (there are function and method types), but not Types themselves.


Sledge(Posted 2007) [#6]
wait were you agreeing or disagreeing?

I was agreeing with him but I didn't know it because you edited before I read his correction (so I assumed he was referring to something different)! Par for the course on teh interwebz.

Might be worth comparing enumerated values rather than strings... I think string comparisons might wind up significantly slower with large numbers of instances. Also, why not separate lists for each type? And which list you total depends on the type parameter passed? (ie check against type once at the start of the process rather than against each instance)

EDIT:
it still leaves me wondering if it _is_ possible to reference to Types like I mentioned

Actually I thought you could... ie when you've got a list containing instances of different types, 'local tempInstance:whatever = eachin myList' would skip anything not of type whatever. Is this not the case? [Looks at SebHoll's code -- yes it is! I'd select...case the temp instance that you traverse the list with, then, if you must have a single list. It'll be ugly but at least it can all be in one function rather than spread over various methods]


snation(Posted 2007) [#7]
Hello Spacerat,

Look at docs on "User Defined Types", relevant quote:
"The Extends part is optional. If omitted, the user defined type extends the built in Object type."

This probably doesn't accomplish exactly what you want, but, may start you towards where you wanna go with it.

I modified your code above as follows:

Type TBall
Method New()
Objects.Addlast(Self)
EndMethod
EndType

Type TDrWatson
Method New()
Objects.Addlast(Self)
EndMethod
EndType

'Here:
Function ObjectCount:Int()
Local num:Int
For Local o:Object = EachIn Objects
num:+1
Next
Return num
End Function
'end modified code.

Global Objects:TList=New TList

New TBall
New TBall
New TDrWatson

Print ObjectCount()
Print ObjectCount()
=======

Runs and returns 3 and 3 again.

Hope it helps.