Bug Abstract - is this working correctly?

Techie42

New member
Joined
Sep 29, 2021
Messages
5
Hi,

I'm new to CX, but not new to programming. I only recently discovered CX and I've found it to be a wonderful tool. But, I'm not sure about Abstract; either I'm misunderstanding the way it works, or it isn't working 100%.

For example, if I run this code, it compiles & runs perfectly (Windows 10, Desktop Game, Debug, CX V2021-07-25):

Code:
Strict

Import mojo2

Class BaseShape
    Method throwIt:Void() Abstract
End


Class Shape Extends BaseShape
    
    Method throwIt:Void()
    End
    
End


Class MyApp Extends App
    Field triangle:Shape
    
    Method OnCreate:Int()
        triangle = New Shape()
        
        triangle.throwIt()
        
        Return 0
    End
    
End


Function Main:Int()
    New MyApp
    
    Return 0
End

If I run this code, it also compiles and runs perfectly:

Code:
Strict

Import mojo2

Class BaseShape
    Method throwIt:Void() Abstract
End


Class Shape Extends BaseShape
    
End


Class MyApp Extends App
    Field triangle:Shape
    
    Method OnCreate:Int()
        triangle = New Shape()
        
        Return 0
    End
    
End


Function Main:Int()
    New MyApp
    
    Return 0
End

But, I would expect a compilation error for the second script, as I haven't defined a throwIt() method in class Shape. Surely, the use of Abstract on the class BaseShape requires me to define the method in class Shape, irrespective of whether I use it?

But, if I do define a call to throwIt() in the OnCreate method in class MyApp (just after the triangle assignment), then I receive a compilation error as I would expect, as the override method hasn't been defined in the Shape class:

Code:
Strict

Import mojo2

Class BaseShape
    Method throwIt:Void() Abstract
End


Class Shape Extends BaseShape
    
End


Class MyApp Extends App
    Field triangle:Shape
    
    Method OnCreate:Int()
        triangle = New Shape()
        
        triangle.throwIt()
        
        Return 0
    End
    
End


Function Main:Int()
    New MyApp
    
    Return 0
End

I would expect the use of Abstract to force a compilation error if I haven't defined it in class Shape, whether I call throwIt() or not. Is this how Abstract is expected to work?

The reason for my question is that if I use multiple files, each file containing a single class, and some classes extending others marked as Abstract, then it becomes a bit unwieldy to have to find where I didn't define an override for an abstracted method. In fact, I would expect compilation to fail if I forget to add the override, not fail only when I try to call the method.

I hope all that makes sense :) Sorry if this is a daft query, but I just need to clear up any misunderstanding on my part as it has a direct bearing on how I use CX.
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
856
Hello and welcome

First thing to note is that Cerberus is not a full fledged compiler, but a transpiler with limited error checking. It will only parse code and thus do error checking if that code is actually being used from the main code. This would mean any methods or function not being used will not be translated into the final source file that will be passed to the backend compiler tool chain.

I'm sure that at one point there was an explanation of this behaviour buried in the documentation somewhere.
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
644
I'm sure that at one point there was an explanation of this behaviour buried in the documentation somewhere.
It's under Advanced Topics -> Optimisation. I know the caption is not well chosen, but there you find some examples of what the transpiler refuses to transpile.
 

dawlane

Well-known member
CX Code Contributor
Joined
Jun 21, 2017
Messages
856
@Phil7 : I knew it was in there somewhere. Been a long time since I had to look at the docs.
 

Techie42

New member
Joined
Sep 29, 2021
Messages
5
Thanks very much for your quick replies ... at least I now know this is expected behaviour (y)
 

Techie42

New member
Joined
Sep 29, 2021
Messages
5
Sorry to revisit this so quickly. I understand what you say about transpiling, but the docs say this:

The Abstract keyword declares that a method must be implemented by extending classes. An abstract method also implies that the container class is abstract; this means that objects cannot be created from the resulting abstract class. Objects may only be created from classes that a) extend this class and b) implement the abstract method.

I would have thought the fact that I have declared an Abstract method, extended the abstract class, and then declared & used an object variable of the extended class type ... that something somewhere would have flagged an error as I haven't implemented the Abstract method in an extending class.

But I'm assuming that as I haven't tried to call the abstract method anywhere, that the transpiler does not flag it as an error ... seems odd.

This really does feel like Abstract is broken, according to what the docs state ... as I have not implemented an abstract method in an extending class. I have done exactly what the docs say I should not be able to do ;) Surely this is the definition of a bug?
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
644
You are right it somehow feels like a but or at least like the compiler is missing an obvious error. But from a practical standpoint where do you see the problem. I can only imagine a problem if you are writing code top down. Starting with the overall structure without implementation of functionality and testing. Maybe I just didn't run into any issues with this so far.
 

Techie42

New member
Joined
Sep 29, 2021
Messages
5
For example, the old tried & tested "Shape" base class which requires certain abstract methods such as area(), perimeter(), etc... then extending that with classes such as Circle, Triangle, Square, etc... The base class could also implement other non-abstract methods, such as circumscribe for a polygon, centroid for a polygon, etc...

Then each extending class would have to implement the abstract methods whilst retaining access to the non-abstract methods.

At some point, I might want to add further base abstract methods, such as volume (if I change from 2D to 3D shapes), so it would be good if the transpiler told me when I'd forgotten to implement the abstract method in any extending classes.

The above is just a simple example of when I would expect the transpiler to help me ;)

If I took the concept further, then I might want to create my own libraries which evolve & mature over time. They could be used by multiple projects, and I would have to ensure that I don't break anything. Again, I would expect the transpiler to flag this.

I hope that makes sense :)
 

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
3,168
Welcome. Look into using reflections and filter it on your files. This way everything is included and SHOULD throw an error.
 

MikeHart

Administrator
Joined
Jun 19, 2017
Messages
3,168
Adding to that, I see it as a bug. Thanks for reporting it. But fixing it... might be VERY difficult.
 
Top Bottom