Self. inside a child extends class don't work

Monkey Forums/Monkey Programming/Self. inside a child extends class don't work

GC-Martijn(Posted 2012) [#1]
Is this a bug ?

The Self. inside a child (Extends) class don't work sometimes.
In the example below its working only for the Field [test] but not for the Field [objs]

I have found how to work with it, but I don't know if this is the best/fastest way to do it.


Class Blocks
	Field objs:List<Block> = New List<Block>
        Field test:Int = 2
End

Class Block Extends Blocks

   Method OnUpdate:Int()
     Print(Self.test) ' can show number 2 - is oke

     For Local block:= Eachin Self.objs
	Print("hey") ' does nothing !
     Next
   End Method

End


To fix this 'problem' I have to use a extra Field and give the parent class object when I create the child object.
But will this slow down or give errors later ?

Class Blocks
	Field objs:List<Block> = New List<Block>
        Field test:Int = 2
End

Class Block Extends Blocks
     Field parent:Blocks

    Method New(inpParent:Blocks) ' give the parent
		parent=inpParent
     End Method

     Method OnUpdate:Int()
     
       Print(Self.test) ' can show number 2 - is oke

        For Local block:= Eachin parent.objs
        	Print("hey") ' works !
        Next
    End Method

End


Thanks for the info


Goodlookinguy(Posted 2012) [#2]
Field objs:List<Block> = New List<Block>


This line shouldn't work because you can't initialize an object at field declaration time.

This will work.

Class Blocks
	Field objs:List<Block>
	Field test:Int = 2
	
	Method New()
		objs = New List<Block>()
	End
End


And even if you have a constructor for a class extending "Blocks", that constructor with no parameters will always be run from each class inherited.

I'd also like to note that in your example, here
	For Local block:= Eachin Self.objs
		Print("hey") ' does nothing !
	Next

That there is nothing in it to begin with, so I don't see why it would do anything. Maybe you cut down the example too much.


GC-Martijn(Posted 2012) [#3]
Oke I made a new example, btw the
Field objs:List<Block> = New List<Block>
does work, but I will change it your way. to make it future proof.

You can copy/past this in monkey
What I see now is 2 things
- When creating a New Block() it triggers the parent class: New()
This is a little weird because I'm creating a extended child class object, and don't want a new Parent object

- the Self.objs inside the Extended class object still count 0 (but I made 2)

Strict
Import mojo

Class Blocks
	Field objs:List<Block>
	Field test:Int = 2
	Field InternBlockCount:Int = 0
	
	
	Method New()
		Print("Create Class object Blocks")
		objs = New List<Block>()
	End
	
	Method AddBlock:Void()
		Print("Add a new block, count:"+objs.Count()) ' is oke
		InternBlockCount = objs.Count()
		objs.AddLast(New Block()) ' < this triggers the New() above !
	End
	
	Method OnUpdate:Int()
	    ' update each block
		For Local block:= Eachin objs
			block.OnUpdate()
		Next
		
		' and do some other code...
		' for example I want to create a new block here
		' this is not the real code but for showing the problem I create 1 new block
		
		If objs.Count()<=1
			AddBlock() ' now I have 2 blocks, but still no printing ("Hey") below 
		Endif
		
		Return 0
	End
End

Class Block Extends Blocks
	Field x:Float=20.0
	
	Method New()
		Print("Create Class object Block = correct")
	End Method
	
	Method OnUpdate:Int()
'		Print(Self.test) ' can show number 2 - is oke
'		Print(Self.objs.Count()) ' is not oke
'		Print(Self.InternBlockCount) ' is not oke
		
		For Local block:= Eachin Self.objs
			Print("hey"+block.x) ' does nothing , when I have made blocks
     	Next
		Return 0
	End Method
End


'==========================================================
Class MyGame Extends App
	Field Blocks:Blocks
	
	Method OnCreate:Int()
		' Startup code goes here
		SetUpdateRate 60
		
		Print("Create Game")
		Blocks = New Blocks()
		Blocks.AddBlock()
		Return 0
	End
	
	Method OnUpdate:Int()
		Blocks.OnUpdate()
		Return 0
	End
	
	Method OnRender:Int()
		Return 0
	End
End

Function Main:Int()
	New MyGame
	Return 0
End


I think the first problem is because its a extened class, using the same method names (2times New())

I guess I don't want to use the extends and yust add a Field [parent] so it works.


ziggy(Posted 2012) [#4]
This line shouldn't work because you can't initialize an object at field declaration time.
Yes you can! Monkey does cleverly execute initializaion of fields just before calling New, so this is perfectly valid on Monkey.
See example (stdcpp) :
Function Main()
	New Manel
End

Class Manel
	Field myfield:List<String> = New List<String>
	Method New()
		Print myfield.Count()
	End
End

The problem is,as you say, that the above code is iterating the contents of an empty list, so no items to iterate. The "for" block does never execute.


ziggy(Posted 2012) [#5]
I see, the error is that you are not filling the objs field of each child blocks, but you're pretending an interation throug them. each class instance has its own instances of each field. If you want the objs field to be "shared" in all classes instances and child classes, you should declare this field as a global inside the class:

Strict
Import mojo

Class Blocks
	Global objs:List<Block> 'This does not deppend on classes instances or inheritance. It's just a global.
	Field test:Int = 2
	Field InternBlockCount:Int = 0
	
	
	Method New()
		Print("Create Class object Blocks")
		If objs = Null then objs = New List<Block>()
	End
	
	Method AddBlock:Void()
		Print("Add a new block, count:"+objs.Count()) ' is oke
		InternBlockCount = objs.Count()
		objs.AddLast(New Block()) ' < this triggers the New() above !
	End
	
	Method OnUpdate:Int()
	    ' update each block
		For Local block:= Eachin objs
			block.OnUpdate()
		Next
		
		' and do some other code...
		' for example I want to create a new block here
		' this is not the real code but for showing the problem I create 1 new block
		
		If objs.Count()<=1
			AddBlock() ' now I have 2 blocks, but still no printing ("Hey") below 
		Endif
		
		Return 0
	End
End

Class Block Extends Blocks
	Field x:Float=20.0
	
	Method New()
		Print("Create Class object Block = correct")
	End Method
	
	Method OnUpdate:Int()
'		Print(Self.test) ' can show number 2 - is oke
'		Print(Self.objs.Count()) ' is not oke
'		Print(Self.InternBlockCount) ' is not oke
		
		For Local block:= Eachin Self.objs
			Print("hey"+block.x) ' does nothing , when I have made blocks
     	Next
		Return 0
	End Method
End


'==========================================================
Class MyGame Extends App
	Field Blocks:Blocks
	
	Method OnCreate:Int()
		' Startup code goes here
		SetUpdateRate 60
		
		Print("Create Game")
		Blocks = New Blocks()
		Blocks.AddBlock()
		Return 0
	End
	
	Method OnUpdate:Int()
		Blocks.OnUpdate()
		Return 0
	End
	
	Method OnRender:Int()
		Return 0
	End
End

Function Main:Int()
	New MyGame
	Return 0
End



GC-Martijn(Posted 2012) [#6]
A little hard to understand because I can't see the differents between

Field test:Int = 2
and
Global objs:List<Block>
or
Field objs:List<Block>

Is it like this:

[Blocks]
--test=1
--objs
---[ block ]
---[ block ]
---- this block can't see all [Blocks.objs] because its created like **1
---[ block ]

**1
[Blocks]
--test=1
--objs (none at initalization)


uuuh well i can't explain it but I think I get it.
I will make it global and use my first syntaxt creating a field like this:
Field objs:List<Block> = New List<Block>()
so I don't have to use the null code inside the New()

And I learned now that New() is triggerd everytime I create a extended class object


ziggy(Posted 2012) [#7]
A Global inside a class does not tie to the class instance.
Example:
Class MyClass
    Global MyGlobal:String = "Hello world!"
End Class
Function Main()
    Print MyClass.MyGlobal
End Function

See that we do not even need to create an object instance for this to work. In other words, if you want to have ONE list with all objects, it has to be a global. Otherwise each object has its own list (in its own field).


Samah(Posted 2012) [#8]
I think the problem is that a lot of developers who are new to the OO paradigm don't recognise the difference between "class" and "instance".

This might be a way to visualise it:
Think of a class as a rubber stamp, and an ink mark as an instance. If I cut a line in the rubber (think "field"), it'll show up every time you "stamp" it. If I put a sticker on the handle of the stamp (think "global") it belongs to the stamp itself and doesn't affect what's on the paper.


ziggy(Posted 2012) [#9]
Most of this confusion would be solved if self was mandatory for instance-member access and classname was mandatory for shared-member access.