Object Problem...

BlitzMax Forums/BlitzMax Beginners Area/Object Problem...

I've made an example of a problem I'm having:
SuperStrict

Type TFoo

	Global FooList:TList=New TList

End Type

Type TBar Extends TFoo

	Field BarList:TList

End Type

Type TBaz

	Field bar:Object
	
	Method Bazzy(barobj:Object)
	
		bar=barobj
	
	End Method
	
	Method BazListify()
	
		ListAddFirst(bar.BarList,Self)	'Self' is just there because I need an object for this example.
	
	End Method

End Type


It tells me 'BarList' does not exist. How do I identify the BarList of the object 'unit' properly? Shouldn't this code at least compile?

The field Bar is an Object and Objects don't have a BarList field so it doesn't exist. You need to cast it to a TBar before you can access the BarList. See below.
SuperStrict

Type TFoo

	Global FooList:TList=New TList

End Type

Type TBar Extends TFoo

	Field BarList:TList

End Type

Type TBaz

	Field bar:Object
	
	Method Bazzy(barobj:Object)
	
		bar=barobj
	
	End Method
	
	Method BazListify()
	
		ListAddFirst(TBar(bar).BarList,Self)	'Self' is just there because I need an object for this example.
	
	End Method

End Type


Ah, thanks!

Hello

Barlist is not initialized. It contains null
You need previously use write
BarList=new TList

Bye,
Paposo

Kind of relatedly, I find something weird:

This is possible:

Type Base
 Method DoSomething:Base()
 End Method
End Type

Type Derived Extends Base
 Method DoSomething:Derived()
 End Method
End Type


This is not:

Type Base
 Method DoSomething(other:Base)
 End Method
End Type

Type Derived Extends Base
 Method DoSomething(other:Derived)
 End Method
End Type


Edit: Forgot Extend

Not sure what you're saying there Otus. They both work for me. What makes the second one 'not possible'?

I think he forgot the extends Base

And the reason it does not work: BM has no overloading so you can not have the same method with different types accepting than the original definition for this scope.

Yes but you didn't explain why it works for the return type.
It is good, and safe that it works for the return type : it's called covariance.
By example it allows to oevverride a "Clone" method that whose return type is always the right one (the same as the type of its containing type).
That is, you can do
Type Base
	Method Clone:Base()
		Local obj:Base = New Base
		' here, copy fields
		Return obj
	End Method
End Type

Type Derived Extends Base
	Method Clone:Derived() ' Return type is 'Derived' even though you override the method in Base, whose return type is 'Base'
		Local obj:Derived = New Derived
		' here, copy fields
		Return obj
	End Method
End Type

Beyond being usefull, allowing this is also safe as in every possible case the real type of the return value for Clone is a derived type (or exactly the type) expected by the compiler. And is thus trivially convertible to the expected type. This wouldn't hold true for parameters.
If modifying the type of parameters in an overriding method was allowed, you would subvert the type system, and would have nice little crashes.

Type Base
	Method DoSomething(other:Base)
	End Method
End Type

Type Derived Extends Base
	Method DoSomething(other:Derived)
	End Method
End Type


Local objBase:Base = New Base
Local objDerived:Base = New Derived	'  'Derived' type instance, but reference decalred as 'Base'
objDerived.DoSomething(objBase)

Let's say the compiler accepts the overriding in 'Derived'
Then at the last line, the call to DoSomething would lead to calling Derived.DoSomething (not Base.DoSometing) as expeected. The compiler wouldn't complain on that line, because at compile time the compiler sees objDerived as a reference to an instance of 'Base' (not 'Derived'). So it will check the call agains Base.DoSomething, and say "mm ok, it expects an instance of 'Base' as a parameter, that's waht I'm given so it's fine". Excepts that at runtime it's not Base.DoSomething that gets called, it's Derived.DoSomething.
Thus Derived.DoSomething will work on 'other' just as if it was an instance of 'Derived', but ti's not. It's an instance of 'Base'. You'd better not try to access a field only declared in 'Derived' and not in 'Base'...

It's a classical problem when mixing two different concpets: static type (as known by the compiler) and dynamic type (the effective type of an object at runtime).

Yeah, forgot extends, of course.

That's a very good explanation Koriolis, thanks.