Treat the returned Type of Method in exteded Type

BlitzMax Forums/BlitzMax Beginners Area/Treat the returned Type of Method in exteded Type

Abomination(Posted 2012) [#1]

I know the method "Sour" will return a TFuit in all extended Types.
So how do can I "construct" the TFruit-type, so any extended types can access the sour-method?
Or will I have to give all extended Types their own Sour-method?
Thanks in advance for any guidance.
p.s. Could I have written the line: "Local test2:TApple =Apple.Sour()" in such a way that it would not generate an error?


PowerPC603(Posted 2012) [#2]
Type TFruit
	Field Taste:String
	Method Sour:TFruit()
		Local Yuck:TFruit=New TFruit
		Yuck.Taste="yum"
		Return  Yuck
	End Method	
EndType

Type TApple Extends TFruit
EndType

Local Fruit:TFruit =New TFruit
 Local test:Tfruit=Fruit.Sour()
Print test.Taste

Local Apple:TFruit =New TApple 
Local test2:TFruit =Apple.Sour()
Print test2.Taste


You can make the Apple and test2 variables a TFruit type, but store a TApple in them.
These variables can also hold any extended type of TFruit, as any extended type is basically a TFruit with some extra options.

Last edited 2012


Abomination(Posted 2012) [#3]
Thanks. That aswers my "p.s"-question.
But I cinda wanted the apple to stay a TApple, so I can get to methods specific for TApple:

Or should I not do that like that?


Yasha(Posted 2012) [#4]
With two changes, you can make this work:



The ReNew method wraps the constructor for each type so that objects can create more of themselves, regardless of whether the calling code knows what type they are. This saves you calling New TFruit and not getting another TApple, by giving the old object control over which type will be created. Normally you'd see something like this in a Copy method.

In the last line, you can't call a TApple method on a TFruit. Even if the TFruit is a TApple, the compiler doesn't know that this is valid. So you must manually downcast to TApple first (which 1. provides enough information that the compiler can actually generate code for this - it literally can't in the original; and 2. assures it that this is OK). If for some reason the TFruit is not a TApple, this will crash. For this reason downcasting is generally considered a Bad Thing (you will need it sometimes, but not as often as you think, if you can, as far as possible, leave control in the hands of the object itself).


Jesse(Posted 2012) [#5]
@abomination
when using extended type as base type, you should not be trying to access them like that. it's best to access them trough abstract methods instead of directly.

Last edited 2012


Abomination(Posted 2012) [#6]
@both: Thanks.
So if I understand correctly, it is better (as a matter of good practice)to give extended types their own Methods, instead of inheriting them? Or only methods that return a custom Type?
For instance: I have a type that deals with an array of objects. So if I want extended types to use an array of custom types instead of objects, I'd have to give them their own methods to return those custom types?


Jesse(Posted 2012) [#7]
if you encapsulate the object, say for example, you want to print specific properties of an extended class, its best to use a common method such as draw(). within the draw you you can output specific information about the object and don't have to worry about knowing what kind of object it is. the object will take care of its own but for this you have to include an abstract method in the base class. if all of the objects have their own draw method then when you call the draw on an object then it will automatically draw the correct information.

Last edited 2012


Abomination(Posted 2012) [#8]
I thought I knew what you meant, but now I'm not that sure anymore.
Do you mean something like this?

I must admit that I don't see the advantage of inheritance.(in this case)
Apple and Fruit could just as well have been unrelated.
Surely I miss something. (a working brain?)("I feel stupider and stupider", says Alice) ;)

Last edited 2012


Jesse(Posted 2012) [#9]
see if this example helps:
[bbcode]


Strict
Type TFruit
Field name:String
Field taste:String
Field color:String
Field plant:String

Method Render()
Print "name: " + name
Print " taste: " + taste
Print " color: " + color
Print " plant: " + plant
End Method
End Type

Type TApple Extends TFruit
Field comment:String

Method New()
name = "Apple"
taste = "Sweet"
color = "Red"
plant = "Tree"
comment = "Healthy eating snack"
End Method

Method Render()
Super.Render()
Print "comment: " + comment
End Method

End Type


Type TLemon Extends TFruit
Field uses:String

Method New()
name = "Lemon"
taste = "Sour"
color = "yellow"
plant = "Tree"
uses = "condiment"
End Method

Method Render()
Super.Render()
Print "use for: "+uses
End Method

End Type


Type TBanana Extends TFruit
Field favoriteRecipe:String

Method New()
name = "Banana"
taste = "sweet"
color = "yellow"
plant = "tree"
favoriteRecipe = "Banana Pudding"
End Method

Method Render()
Super.Render()
Print "favorite Recipe "+ favoriteRecipe
End Method

End Type


Local list:TList = New TList

list.AddLast(New TApple)
list.AddLast(New TLemon)
list.AddLast(New TBanana)

For Local f:TFruit = EachIn list
f.Render()

Print
Print
Next
[/bbcode]


Yasha(Posted 2012) [#10]
Apple and Fruit could just as well have been unrelated.


In the code as it stands, yes. Now change the third and fourth-last lines to this:

Local Apple:TFruit =New TApple 
Local test2:TFruit =Apple.Sour()


The compiler is no longer expecting TApples. Now it's just seeing TFruit and expecting them to do the right things based on their internal methods. It still works, but by removing the information about which particular fruit is implemented, it delegates responsibility to the object to decide what to do.

The term for this is "polymorphism", and it is OOP (not "part of": code that isn't polymorphic is not object-oriented). Objects decide to do based on their internal methods without being directed what to do by the code around them, which means that when different objects pass through the same bit of code, they can decide to do different things.

(It is linked to inheritance by a quirk of BlitzMax design, but isn't really related to it in the strict sense.)

Look up polymorphism examples to get why this is useful. You've really set up this example in a way that kinda second-guesses the whole point of the feature, which is why it doesn't showcase the advantages of it very well.


Abomination(Posted 2012) [#11]
@Yasha: Wait!... Give me a moment......... By Jove, I think I've got It. ;)
So, if the original type returns Fruit in a method and in an extended type a method returns Apple. Then if I access either method in the extended one, I get an apple AND a fruit, so I should look for a fruit and treat it as an apple.
(I feel a bit fruity)
@Jesse: Thanks for that example, but that is just the part of "types" that I DO understand. The part of "how to treat the type of a returned value", is what wass troubling me.
I still don't see how the use of abstract can help here? Apart of creating a format the extended types have to "obey".
I feel like I have improved my blitzmax skills a bit over the past few hours. At least I know why my original example is wrong.
(I will jump into the night and fiddle with my code.)<-(famous Japanese saying.)


Jesse(Posted 2012) [#12]
"Abstract" helps the base class understand that when you create an extended class, the extended class will have the specified function or method.
for example if you have an extended object that has an update() method but there is no update method in the base class then by creating the abstract update() method in the base class, access is given to the base class about that specific extended part of the object. If you don't declare the abstract you wont be able to access the extended part of the object while it's casted as the base class.

Note that a requirement of an abstract method/function is that it required that every extended class have that specific method. In the case of the Update(), every extended object will have to have the update() method.

Last edited 2012