Abstract

BlitzMax Forums/BlitzMax Beginners Area/Abstract

MadMax(Posted 2005) [#1]
What's the use of Abstract? As there is no real need to define a method or function in the base object, you still have to redefine it in the extended type.

Also if you have a create function, the extended type won't be created unless you have a create function for the extended type.


FlameDuck(Posted 2005) [#2]
What's the use of Abstract?
You use Abstract to define a methods interface. Since Abstract methods must be implemented in any concrete class (that is, a class that is instanced), you can invoke the Abstract methods safely.


Lomat(Posted 2005) [#3]
The point of Abstract is that you saying that you are not allowed to directly create the type in question but that any child types must implement all abstract methods exactly as you have defined them.

So if we take a quick example lets say that we need a number of different bullets in our game, to keep it simple they all work the same way but they render differently. The first step would be to define a base bullet type like so...

Type Bullet
	
	Field x:Float  = 0
	Field y:Float  = 0
	Field dX:Float = 0.1
	Field dY:Float = 0
	
	Method setPosition(newX:Float, newY:Float)
		x = newX
		y = newY
	End Method
	
	Method update ()
		x = x + dX
		y = y + dY
	End Method
	
	Method render () Abstract
	
End Type


This type would define all the shared functionality that each bullet needs and also defines what you could describe as an interface that we know will exist in any child type, in this example the render() method. So now we would define all our child types like so...

Type SimpleBullet Extends Bullet

	Method render()
		DrawOval(x, y, 10, 5)
	End Method

End Type

Type BlockBullet Extends Bullet

	Method render()
		DrawRect(x, y, 5, 5)
	End Method

End Type



So now we have our bullets defined and we know exactly what methods are available to us. So in our project we can define the variables like so...

Local b1:Bullet = New SimpleBullet
Local b2:Bullet = New SimpleBullet
Local b3:Bullet = New BlockBullet
Local b4:Bullet = New BlockBullet

b1.render()
b2.render()
b3.render()
b4.render()


Now because we have defined the abstract render method we do not get the "Identifier 'render' not found" message when we try to compile the project.

As for a create function if really depends on what exactly is required to be done when each of the different types are created. But lets say that all of our bullets are created in the same way and that they will all be created from the base Bullet type with a create method. The step do do this are:

1. Create the method and define the return type as Bullet. This will allow us to return any child type.
2. Check what type of bullet we want and create it.
3. Configure the new bullet and return.

Therefore you could do something like...

Type Bullet
	'... Existing Bullet type code above here ...
	Function create:Bullet(what:String, newX:Float, newY:Float)
		Local b:Bullet
		Select what
			Case "block"
				b = New BlockBullet
			Case "simple"
				b = New SimpleBullet
			Default
				RuntimeError("Invalid bullet type specified.")
		End Select
		b.setPosition(newX, newY)
		Return b
	End Function 
End Type


Which we could then use like so...

Local b1:Bullet = Bullet.create("simple", 10, 10)
Local b2:Bullet = Bullet.create("simple", 10, 10)
Local b3:Bullet = Bullet.create("block", 10, 10)
Local b4:Bullet = Bullet.create("block", 10, 10)

b1.render()
b2.render()
b3.render()
b4.render()


As you should be able to see you can now create any bullet type you like and not really have to worry about it in other parts of you code as all you will be specifying is that it is a bullet and because of the abstract methods each bullet type can work differently internally but on the outside they are all exactly the same freeing you from having to constantly code around all the different bullet types in your project.

I hope this helps. :)


Lomat(Posted 2005) [#4]
FYI. A little example...

Type Bullet
	
	Field x:Float  = 0
	Field y:Float  = 0
	Field dX:Float = 1.0
	Field dY:Float = 0.5
	
	Method setPosition(newX:Float, newY:Float)
		x = newX
		y = newY
	End Method
	
	Method update ()
		x = x + dX
		y = y + dY
	End Method
	
	Method render () Abstract
	
	Function create:Bullet(what:String, newX:Float, newY:Float)
		Local b:Bullet
		Select what
			Case "block"
				b = New BlockBullet
			Case "simple"
				b = New SimpleBullet
			Default
				RuntimeError("Invalid bullet type specified.")
		End Select
		b.setPosition(newX, newY)
		Return b
	End Function 
	
End Type


Type SimpleBullet Extends Bullet

	Method render()
		Print("o ("+x+","+y+")")
	End Method

End Type

Type BlockBullet Extends Bullet

	Method render()
		Print("= ("+x+","+y+")")
	End Method

End Type

Local b1:Bullet = Bullet.create("simple", 10, 10)
Local b2:Bullet = Bullet.create("simple", 10, 100)
Local b3:Bullet = Bullet.create("block", 200, 10)
Local b4:Bullet = Bullet.create("block", 10, 20)

b1.render()
b2.render()
b3.render()
b4.render()

Print("++++++++++++++++++++")
b1.update()
b2.update()
b3.update()
b4.update()

b1.render()
b2.render()
b3.render()
b4.render()



MadMax(Posted 2005) [#5]
Well, thank you very much, this helps greatly.

@Lomat,, Great code, simple and to the point. This will help me a lot, specialy the create bit. I hadn't realized that methods would accept parametres. So if I am not confused methods seem to be confined to the element(s) in the type, and functions to the type itself.

Odd this OOP business, seems more difficult to explain than to understand.


Lomat(Posted 2005) [#6]
Type methods act on an instance of a type. e.g.

Local b:Bullet = new SimpleBullet
b.myMethod()

Type functions are static, i.e. you can call/use them anywhere and they are not linked to any instance of that type.

Bullet.myFunction()


SoggyP(Posted 2005) [#7]
Hello.

7 fish.

Goodbye.


Dubious Drewski(Posted 2005) [#8]
That was excellent, Lomat. Anyone who asks from now on should be directed here.


Ferminho(Posted 2005) [#9]
Great explanation!
Why not include somewhere in the wiki? could be a good reference for beginners