Overriding Methods of Types in Modules

BlitzMax Forums/BlitzMax Programming/Overriding Methods of Types in Modules

mk2y10(Posted 2014) [#1]
I am currently working on a small GUI system, but am having trouble overriding methods of types that extend imported types.

File 'A.bmx':

Module mymod.a

Public

Type Something
   
   Method Do()
   
      Print "A"
   
   End Method
   
End Type



File 'B.bmx':
Public

Import MyMod.A

Local S:Something2 = New Something2
S.Do()    'Should print B, but prints A.


Type Something2 Extends Something
   
   Method Do()
      
      Print "B"
      
   End Method
   
End Type



If you run file B, it prints A instead of B, meaning the method is not overriding the module's type's method.


Derron(Posted 2014) [#2]
What does not work ?

import "basetype.bmx"

Type MyType extends BaseType
  Method OverriddenMethod()
  End Method
End Type


works as intended.

bye
Ron


mk2y10(Posted 2014) [#3]
Derron, I went key happy and posted half my topic by accident. I have edited to show the problem. I am overriding a module's type's method.


Derron(Posted 2014) [#4]
Import Brl.RamStream

Type TMyRamStream Extends TRamStream
	Method Size()
		print "overridden"
		Return _size
	End Method
End Type

global mystream:TMyRamStream = new TMyRamStream
print "size: "+mystream.Size()


output:

./bmk makeapp -t console -r -x "/testcodes/extendmodule.bmx"
Compiling:extendmodule.bmx
flat assembler  version 1.68  (32768 kilobytes memory)
3 passes, 5953 bytes.
Linking:extendmodule
Executing:extendmodule
overridden
size: 0



is "B.bmx" a module too ?


bye
Ron


mk2y10(Posted 2014) [#5]
No, file B is the end user's program.


Brucey(Posted 2014) [#6]
Appears to work as expected.

In this example, it will work through different modules too, so the small example applies just the same :
SuperStrict

Framework brl.standardio

Local S:Something = New Something
S.Do() ' A

Local S1:Something = New Something2
S1.Do() ' B

Local S2:Something2 = New Something2
S2.Do() ' B


Type Something
   
   Method Do()
   
      Print "A"
   
   End Method
   
End Type

Type Something2 Extends Something
   
   Method Do()
      
      Print "B"
      
   End Method

End Type


If it isn't working for you then your example does not represent the actual code you are having a problem with - I'd say you probably have a bug in your code that you don't see yet.


mk2y10(Posted 2014) [#7]
Ah, I made a mistake in describing it. The Do method is being called from file A, like so:

File 'A.bmx':

Module mymod.a

Public

Type Something
   
   Method Test()
      
      Do()
      
   End Method
   
   Method Do()
   
      Print "A"
   
   End Method
   
End Type



File 'B.bmx':
Public

Import MyMod.A

Local S:Something2 = New Something2
S.Test()    'Should print B, but prints A.


Type Something2 Extends Something
   
   Method Do()
      
      Print "B"
      
   End Method
   
End Type



Sorry for the lack of intellect on my end :)


Derron(Posted 2014) [#8]
That is something like a "scope".

So when you want to have "Something2.Test()" to call the "Do()" of Something2, you have to override "Test()" too.

Have had this similar in my codes. Not how we expect it to work - but there is surely a reason for such a behaviour.


EDIT: ok ... tested it again, seems still to work:

I edited "RamStream" to have another Method:
	Method MySize()
		Size()
	End Method


Calling "MyRamStream.MySize()" still used the overridden Size()-Method. So dunno what does not work for you.


EDIT2: Could you give a little bit more detail how you create the extended object? Maybe its "original" type is the ancestor instead of the extended one ... in that case the behaviour would be absolutely correct.

bye
Ron


mk2y10(Posted 2014) [#9]
It worked? Well that is good news, but also bad. Good as in it works like I expected, but bad because it doesn't work on my end.

I will copy my code and see if I did something wrong:





Stepping through with debug only shows execution of the base "jObject" onCreate() method, even though it should be overridden.


Derron(Posted 2014) [#10]
I copied your code.

Output is:

$ ./bmk makemods -a jpi
Compiling:jobject.bmx
flat assembler  version 1.68  (32768 kilobytes memory)
3 passes, 2473 bytes.
Archiving:jobject.debug.linux.x86.a
ar: creating /BlitzMax/mod/jpi.mod/jobject.mod/jobject.debug.linux.x86.a
Compiling:jobject.bmx
flat assembler  version 1.68  (32768 kilobytes memory)
3 passes, 1638 bytes.
Archiving:jobject.release.linux.x86.a
ar: creating /BlitzMax/mod/jpi.mod/jobject.mod/jobject.release.linux.x86.a


$ ./bmk makeapp -t console -r -x "/testcodes/extendmodule2.bmx"
Compiling:extendmodule2.bmx
flat assembler  version 1.68  (32768 kilobytes memory)
3 passes, 4006 bytes.
Linking:extendmodule2
Executing:extendmodule2

MyObject Error



Seems to work.


Brucey(Posted 2014) [#11]
Yes, it's a scope issue. You should probably make onCreate() in your jObject class Abstract. (which is possible if you are never likely to create an instance of jObject).

Calling onCreate() frin jObject's Init() method will call the locally scoped onCreate() in preference to one in a subclass.

So, something like this :
Type jObject
	
	Method Init()
		onCreate()
	End Method
	
	Method onCreate() Abstract
	
End Type



mk2y10(Posted 2014) [#12]
If it works for you then it must be something on my end i'm afraid :/

Build Modules Output:
Building Modules
Compiling:jobject.bmx
flat assembler  version 1.69.14  (1048575 kilobytes memory)
3 passes, 2316 bytes.
Archiving:jobject.debug.mt.win32.x86.a
flat assembler  version 1.69.14  (1048575 kilobytes memory)
3 passes, 4058 bytes.
ar: creating C:/BlitzMax/mod/jpi.mod/jobject.mod/jobject.debug.mt.win32.x86.a
Compiling:jobject.bmx
flat assembler  version 1.69.14  (1048575 kilobytes memory)
3 passes, 1343 bytes.
Archiving:jobject.release.mt.win32.x86.a
flat assembler  version 1.69.14  (1048575 kilobytes memory)
3 passes, 1789 bytes.
ar: creating C:/BlitzMax/mod/jpi.mod/jobject.mod/jobject.release.mt.win32.x86.a

Process complete



My output:
Building untitled3
Compiling:untitled3.bmx
flat assembler  version 1.69.14  (1048575 kilobytes memory)
3 passes, 3850 bytes.
Linking:untitled3.debug.mt.exe
Executing:untitled3.debug.mt.exe

>>"Object Error" MessageBox Here<<

Process terminated



Not sure what is wrong, but I guess the hunt begins.


EDIT: Just saw Brucey's answer.

Changing onCreate in the jObject type to abstract gives an "Unhanded Exception:Attempt to call abstract method." error.


Derron(Posted 2014) [#13]
Which means somehow you want to call the "jobject"'s method "onCreate".


Does the code you gave me work for you (or do you have more code in it) ?

I freshly create a module dir for your module .. and a new example.bmx just containing the second code block you posted.

This was the one that worked for me.



bye
Ron


mk2y10(Posted 2014) [#14]
Nope, it does not work for me. I created a fresh module and used the same code, and it always wants to use the method inside the import. It is like the "Import Whatever.Mod" acts like a wall or something. Hell, I'm not even sure where to start looking for what's causing it. Is this something with MinGW?

God I hope not :(


Derron(Posted 2014) [#15]
MinGW is only used for "C".

Are you using an up-to-date BlitzMax?

Do you use a custom bmk/bcc (eg. Brucey "NG"-project) ?

Does it happen for "non-mt-builds" too (should not change anything) ?


bye
Ron


mk2y10(Posted 2014) [#16]
This is a fresh install of Max Version 1.50

It was installed in C:\BlitzMax, and I deleted the older version, so nothing should be bad there. I am also using the MaxIDE that came with the install.

I have no third party mods other than the one I made (jpi.jobject shows up under Help>>>Third Party Modules)

Yes, it happens with all builds, even non-mt and release.

I'm installing a few older versions of max to see if one somehow works. *crosses fingers*


Derron(Posted 2014) [#17]
I meanwhile tried it in my Windows setup:

Building untitled1
Compiling:untitled1.bmx
flat assembler  version 1.69.14  (1146432 kilobytes memory)
3 passes, 3301 bytes.
Linking:untitled1.exe
Executing:untitled1.exe
MyObject Error
Process complete



C:\Tools\BlitzMax\bin>bmk -v
bmk 2.15 mt-win32-x86 / gcc 40601 (cpu x1)

C:\Tools\BlitzMax\bin>bcc -v
BlitzMax Release Version 1.48


So in this case I am using "1.48". But the only important thing in 1.50 bcc-changes was the fix of the REM-comment-bug which seems to only happen on XP machines.


bye
Ron


mk2y10(Posted 2014) [#18]
After fiddling with constantly rebuilding all the modules, I just went and rebuild them with my older version of MinGW. Now, it overrides the correct methods for some reason (not sure how that works if anyone can explain?)

One thing I did notice though is the test does not work for the new() method, like so:





I am not sure if that is a bug or the New() method specifically is designed that way. I thank you for your help though guys!


Brucey(Posted 2014) [#19]
New() is different. There is, in reality, one New() method for each class, subclass, etc.

When the class is instantiated, It first calls New() on its parent, which calls New() on its parent, and so on. When New() of the top-most class is called, say, your jObject, there does not exist a reference yet of a MyObject object. It calls the local onCreate() method.

Here's an example of New() calling the local method :
SuperStrict

Framework brl.standardio

Local x:C = New C


Type A

	Method New()
		OnCreate()
	End Method

	Method OnCreate()
		Print "A"
	End Method
	
End Type

Type B Extends A

	Method New()
		OnCreate()
	End Method

	Method OnCreate()
		Print "B"
	End Method

End Type

Type C Extends B

	Method New()
		OnCreate()
	End Method

	Method OnCreate()
		Print "C"
	End Method

End Type


You can't use New() to call a overridden method in a subclass.