Inheritance and subtyping
If class X extends (inherits from) class Y, you can use a value with type X (the subtype) whenever a value of type Y (the supertype) is expected. For example, io::File inherits from io::Stream. Therefore, the following code is valid:
var s as Stream var f = File('data.txt') as File s = f
As s has type Stream, we can only access members defined in Stream by using s. For example, seek is defined in File but not in Stream:
f.seek(2) -- Ok s.seek(2) -- Error: member "seek" not defined in Stream
The Object type
The Object is the top of the Alore class hierarchy: every other class is a subclass of Object, either directly or via a superclass. Thus any Alore value can be stored in a variable with the Object type:
var o as Object o = 1 -- Ok o = 'x' -- Ok
However, values with the Object type only support a few interesting operations. You can use casts, discussed later in Section Casts, to convert an Object value to a more specific type.
Overriding methods
Overriding with identical signature
If a method overrides a superclass method, the signature of the method must be compatible with the superclass method. In the simple case the signature is identical:
import io class Super def open(path as Str) as Stream return File(path) end end class Sub is Super def open(path as Str) as Stream -- Ok: identical signature return File(path + '.ext') end end
Additional arguments in overriding method
The overriding method may define additional optional arguments compared to the original method signature. Intuitively, the overriding method is still compatible because it can be called with either the original signature or with the additional arguments. Here is an example:
class Super def f(a as Int) ... end def g() as void ... end end class Sub is Super def foo(a as Int, b = '' as Str) -- Ok, since b is optional ... end def g(*args as Int) -- Ok, since args is a varargs argument ... end end
Contravariance and covariance
In addition, the argument types in the subclass may be supertypes of the corresponding supertype method argument (contravariance). Similarly, the return type may be a subtype of the return type of the supertype method (covariance):
class Sub is Super def open(path as Object) as File -- Ok: contravariant argument type, ... -- covariant return value type end end
The above example is valid, since Object (type of path) is a supertype of Str, and the return type File is a subtype of Stream.
Overriding and dynamic
We will discuss how the type dynamic affects overriding later in Section The dynamic type and mixed typing.
Overriding member variables and accessors
A subclass may override member variables and accessors defined in a superclass using accessors. In this case the type in the subclass must be equivalent to the superclass type. This example illustrates it:
class Super var i as Int var o as Object end class Sub is Super def i as Int -- Ok, same type as in superclass ... end def o as Str -- Error: Str incompatible with Object ... end end