These are common object-oriented mechanisms. However, they can make code difficult to understand and have unexpected effects. Therefore we will support them, but see them as the exception. By default methods are non-abstract and non-virtual:
FUNC funcy(ArgType arg): RetType
# this function cannot be replaced in a subclass
FUNC funcy(ArgType arg): RetType @abstract
The body of this function is not defined and makes the class abstract, it can't be instantiated.
FUNC funcy(ArgType arg): RetType @default
# this function can be replaced in a subclass
This function provides a default implementation. Replacing it in a subclass is optional. This does not prevent the class from being instantiated.
An alternative would be to put the attribute before "FUNC":
This has two problems:
Methods without "@abstract" or "@default" cannot be replaced in a subclass. This makes it easier to be sure about what method is actually used, no need to check all subclasses if they replace the method.
This leads to hard to track down bugs. Therefore: defining a function from the base class must be marked with the @define attribute to define an abstract method, and @replace to replace a virtual method.
CLASS FooBase @abstract
FUNC toString(): string @abstract
PROC error() @default
CLASS FooChild EXTENDS FooBase
FUNC toString(): string @define # defining abstract method
PROC error() @replace # replacing default method
IO.write("In FooChild: ")
PROC foo() # new method
Also support inheritance for list, dict and tuple. Example:
CLASS SymbolList EXTENDS list<Symbol>
FUNC find(string name, SymbolType type): Symbol
FOR sym IN PARENT
IF sym.name == name && sym.type == type
This has not been implemented yet.