Field Overrides in Types

BlitzMax Forums/BlitzMax Programming/Field Overrides in Types

I'm trying to come to grips with how Extensions of Abstract Types handle Fields. The Methods of Extended Types replace the Abstract Methods that they're Extending - that's clear and works fine. However, the same doesn't seem to hold true for Types - at least not all the time.

That is, if I explicitly assign a default value to a Field in an Extending Type, it does not override the default value in the Abstract Field. But, if I don't put a Field entry at all in the Extending Type, then it does override the Abstract Field (when assigned by other means).

An example:
Strict


Type TGeneric Abstract
	Field MyType$ = "generic"
	Method GetType() Abstract
End Type


Type TSpecific Extends TGeneric

	Field MyType$ = "specific" 'COMMENT THIS LINE OUT TO CHANGE BEHAVIOR

	Function Create:TSpecific()
		Local c:TSpecific=New TSpecific
		c.MyType="specific"
		Return c
	End Function

	Method GetType()
		Print "I'm specific (" + MyType + ")"
	End Method

End Type


'Two functions to access MyType, one takes a TGeneric parameter while the other takes a TSpecific

Function PrintGeneric ( thing:TGeneric )
	Print "PrintGeneric: MyType="+thing.MyType
	thing.GetType
End Function


Function PrintSpecific ( thing:TSpecific )
	Print "PrintSpecific: MyType="+thing.MyType
	thing.GetType
End Function


'Three ways of creating a new instance of TSpecific:

Local Specific1:TSpecific = New TSpecific

Local Specific2:TSpecific = New TSpecific
Specific2.MyType = "specific"

Local Specific3:TSpecific = TSpecific.Create()


Print
Print "Specific1:"
PrintGeneric( Specific1 )
PrintSpecific( Specific1 )

Print
Print "Specific2:"
PrintGeneric( Specific2 )
PrintSpecific( Specific2 )

Print
Print "Specific3:"
PrintGeneric( Specific3 )
PrintSpecific( Specific3 )


The code above produces this output:
Specific1:
PrintGeneric: MyType=generic
I'm specific (specific)
PrintSpecific: MyType=specific
I'm specific (specific)

Specific2:
PrintGeneric: MyType=generic
I'm specific (specific)
PrintSpecific: MyType=specific
I'm specific (specific)

Specific3:
PrintGeneric: MyType=generic
I'm specific (specific)
PrintSpecific: MyType=specific
I'm specific (specific)

So, there's no way to directly access MyType with a result of "specific" when passing it as TGeneric, though its GetType Methods will always return "specific."

However, if you comment out the indicated line in TSpecific - the one that assigns a default value of "specific" to MyType - then the results are different:
Specific1:
PrintGeneric: MyType=generic
I'm specific (generic)
PrintSpecific: MyType=generic
I'm specific (generic)

Specific2:
PrintGeneric: MyType=specific
I'm specific (specific)
PrintSpecific: MyType=specific
I'm specific (specific)

Specific3:
PrintGeneric: MyType=specific
I'm specific (specific)
PrintSpecific: MyType=specific
I'm specific (specific)


Now it is possible to directly return a value of "specific" from MyType (except for Specific1 where it's never assigned and is thus correctly always returned as "generic").

Why is it that explicitly defining Field MyType$ = "specific" doesn't work, while leaving it out does work as I'd think it should?

Update: Is it that if it's defined again, there are two different MyType$s that are accessed depending on the "scope" of the item doing the accessing (TGeneric vs. TSpecific)?

Heh, answered my own question (once I understood enough to ask the second, updated question above). Yes, it's scope-dependent - now everything is clear to me. The modified code below shows this for anyone else flummoxed by this as I was:
Strict


Type TGeneric Abstract

	Field MyType$ = "generic"

	Method SpecMyType() Abstract
	
	Method GenMyType()
		Print "GenMyType: "+MyType
	End Method

End Type


Type TSpecific Extends TGeneric

	Field MyType$ = "specific" 'COMMENT THIS LINE OUT TO CHANGE BEHAVIOR

	Function Create:TSpecific()
		Local c:TSpecific=New TSpecific
		c.MyType="specific"
		Return c
	End Function

	Method SpecMyType()
		Print "SpecMyType: "+MyType
	End Method

End Type


'Two functions to access MyType, one takes a TGeneric parameter while the other takes a TSpecific

Function PrintGeneric ( thing:TGeneric )
	Print "PrintGeneric: MyType="+thing.MyType
	thing.GenMyType
	thing.SpecMyType
End Function


Function PrintSpecific ( thing:TSpecific )
	Print "PrintSpecific: MyType="+thing.MyType
	thing.GenMyType
	thing.SpecMyType
End Function


'Three ways of creating a new instance of TSpecific:

Local Specific1:TSpecific = New TSpecific

Local Specific2:TSpecific = New TSpecific
Specific2.MyType = "specific"

Local Specific3:TSpecific = TSpecific.Create()


Print
Print "Specific1:"
PrintGeneric( Specific1 )
PrintSpecific( Specific1 )

Print
Print "Specific2:"
PrintGeneric( Specific2 )
PrintSpecific( Specific2 )

Print
Print "Specific3:"
PrintGeneric( Specific3 )
PrintSpecific( Specific3 )


What was tripping me up was that I wanted to be able to pass Specific instances as TGeneric items, so that the accepting function could handle additional variations of TGeneric as well. But I was having trouble accessing the overridden MyType when passing them that way (even though the overridden Methods worked as they should).

The reason is that directly accessing MyType when passed as TGeneric was reading the TGeneric-level MyType. This does make sense, but the TSpecific-level Methods were accessible even when passed that way, which confused me. I see now that Methods override, while Fields don't - unless they aren't defined in the Extending Type, in which case they "do" (they aren't really overriding, but instead referring to the higher-level, Abstract, Field).