Call extended type method from base type instance

BlitzMax Forums/BlitzMax Programming/Call extended type method from base type instance

skn3(Posted 2005) [#1]
What ??? ..
Well if you want to create a base type, and extend sub objects from that type.. you will start to run in to some problems when you want to return an extended type as its base type.

An example of what I mean: You have a gui gadget type, called "guigadget". Now this stores the x,y,width,height and lets any other features for a particular gadget (button,scrollbar,textbox,etc) upto the extended type. Now say we create and return a guigadget, but it is actualy guigadget_button type. How would you then call any methods from the extended type ?

Take a look at this code, it might help. This seems like the most viable way to me, but unless Im missing something. Is there a more suitable way of doing this ?

Type fruit
	Field x,y,width,height
	Field _CallUpdate(f:fruit)
	
	Method Update()
		'because the base class update is called, we need to use the method caller stored
		_CallUpdate(Self)
	End Method
End Type

Type apple Extends fruit
	Field brand:String
	
	'creation function
	Function Create:fruit(x,y,width,height,brand:String)
		Local a:apple = New apple
		'setup properties
		a.x = x
		a.y = y
		a.width = width
		a.height = height
		a.brand = brand
		'setup class callers
		a._CallUpdate = apple.CallUpdate
		
		Return a
	End Function
	
	'callers for this class
	Function CallUpdate(f:fruit)
		apple(f).Update()
	End Function
	
	'methods for this class
	Method Update()
		Print "update apple, brand = "+brand
	End Method
End Type

Type grape Extends fruit
	Field numberinbunch
	
	'creation function
	Function Create:fruit(x,y,width,height,bunch)
		Local g:grape = New grape
		'setup properties
		g.x = x
		g.y = y
		g.width = width
		g.height = height
		g.numberinbunch = bunch
		'setup class callers
		g._CallUpdate = grape.CallUpdate
		
		Return g
	End Function
	
	'callers for this class
	Function CallUpdate(f:fruit)
		grape(f).Update()
	End Function
	
	'methods for this class
	Method Update()
		Print "update grape, number in bunch = "+numberinbunch
	End Method
End Type

'now we can create 1 apple and 1 grape, and return them as the base class.
'if we want to call the update function for either, we can, because it has been mapped using a function pointer.
Local fruit1:fruit = apple.Create(0,0,60,60, "golden smith")
Local fruit2:fruit = grape.Create(10,10,60,100, 75)

fruit1.Update()
fruit2.Update()

Input "press enter to end"



Robert(Posted 2005) [#2]
I may be misunderstanding you, but virtual methods take care of this automatically.

It doesn't matter whether fruit1 or fruit2 are defined as Fruit objects or the actual types from which they are instantated.

Type Fruit
	Method whatAmI() Abstract
End Type

Type Apple Extends Fruit
	Method whatAmI()
		Print "I am an apple"
	End Method
End Type

Type Orange Extends Fruit
	Method whatAmI()
		Print "I am an orange"
	End Method
End Type

Local fruit1:Fruit=New Apple
Local fruit2:Fruit=New Orange

fruit1.whatAmI()
fruit2.whatAmI() 



skn3(Posted 2005) [#3]
Ah ha.. duh I am stupid XD


PGF(Posted 2005) [#4]
If you don't have a virtual method in the base type - say when different derived types will implement different methods - then you can check what type the instance is, cast to the proper sub-type and then invoke the method.

Strict

Type Fruit
	Method whatAmI() Abstract
End Type

Type Apple Extends Fruit
	Method whatAmI()
		Print "I am an apple"
	End Method

	Method howManyWorms()
		Print "Only a couple of worms"
	End Method
End Type

Type Orange Extends Fruit
	Method whatAmI()
		Print "I am an orange"
	End Method

	Method howJuicy()
		Print "Very juicy"
	End Method
End Type

Local fruit1:Fruit=New Apple
Local fruit2:Fruit=New Orange

PrintInfo(fruit1)
PrintInfo(fruit2)

Function PrintInfo(thing:Fruit)

	thing.whatAmI()
	
	If Apple(thing)
		Local myApple:Apple = Apple(thing)
		myApple.howManyWorms
	Else
		Local myOrange:Orange = Orange(thing)
		myOrange.howJuicy()
	EndIf
		
End Function



skn3(Posted 2005) [#5]
Yeah I knew that one, was looking for a method that didn't require a comparison against each extended type. Because well, it would mean those extended objects couldn't be further extended without modifying alot of function calls.


Robert(Posted 2005) [#6]
I believe that all methods in BlitzMAX types are virtual or at least Max deals with the virtual business automatically.

This means that you don't need to do anything special with the base class's method in order to replace in in a derived type.

As a rule, the base class should not be aware of or rely on any derived types in any way.

Similarly any functions that accepts an object of the base type as a parameter should not have to know anything about the possible derived types from which the object might actually have been instantated.


PGF(Posted 2005) [#7]
Robert,

I take your point and agree that such independence of the base type from derived types would be ideal.

However this pure approach falls down (IMHO) if it leads you to have a lot of properties and methods in the base type that do not apply in some or even most of the derived types.

So a competing ideal is that a type only contain or provide those properties and methods that make sense for it.

When I want a derived type that introduces a new method say, I don't want to go back through the hierarchy adding it all the way back to the base - abstract or not. And when it is abstract, doesn't each derived type that isn't abstract have to provide an implementation ?

So I'm finding that somewhere between the two ideals is what works in practice.

I'm still learning about this object stuff so I'm happy to hear a different point of view.

I'm working on one project in BlitzMax where there is a deep object hierarchy. Each type in the hierarchy maintains a TList so when I need to apply a method that exists only in a type and its derivatives then I iterate through the appropriate list. I don't iterate through the top level list and check the type before invoking the method if it is appropriate.

It is a bit lengthy to show here but when it is done I plan to submit it for comment. Perhaps somebody could come up with a better design.

PGF