Design‎ > ‎Classes and Interfaces‎ > ‎

Abstract and Virtual methods

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): RetTyp@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":
      ABSTRACT FUNC
      DEFAULT FUNC
This has two problems:
  1. DEFAULT already is used in a SWITCH statement.  It would then need to be called VIRTUAL, which does not have an obvious meaning.
  2. It is harder to read text with several words in capitals.

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.
  • An abstract function must be defined in a subclass.
  • A virtual function can be redefined in a subclass.
  • All other functions can't be redefined in a subclass.

The need for @replace and @define

When modifying code there is a danger of adding a virtual method to a base class while the subclass already has this method, where there was no intention of replacing the method of the base class.  For example, the subclass defines an error() method and the base class doesn't.  When a virtual error() method is added to the base class, this would go unnoticed.  Even though the error() method in the subclass might need to be adjusted for the changed base class.

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
              IO.write("Error!")
           }

        }
        CLASS FooChild EXTENDS FooBase
           FUNC toString(): string @define #  defining abstract method
              RETURN something
           }
           PROC error() @replace          #  replacing default method
              IO.write("In FooChild: ")
              PARENT.error()
           }
           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
                  RETURN sym
                }
              }
            }
         }

This has not been implemented yet.



Comments