Wouldn’t it be nice, if we could define a method like this:
# assuming Iterable{T} is an abstract type in Base,
# and merged into all relevant iterable classes.
function myfindmax(itr::Iterable{T})
println("inferred type $T")
findmax(itr)
end
julia>myfindmax(1:5)
inferred type Int64
(5,5)
And would then expect some statements to be true:
- the method is called only for
itr
objects, which “are”Iterable
s. Which means, there is a contract, assuring us, that we can callstart
,next
,done
, andeltype
for ouritr
. - we (and the compiler) can assume, that
next(itr, i)
returns an element of typeT
.
Now, there are may abstract types and data types, which “are” iterable. They respect the Iterable
’s contract, but is is not manifested in the code. Nor is it possible to dispatch the methods according to this.
Now, AbstractArray
for sure has more important properties, than being iterable, and there are many other types, which are important on their own, but as a matter of course are also iterable. Attaching such common properties is possible in other languages using multiple inheritance (C++) and traits (Scala). There are some technical difficulties in the implementation in those languages, due to the complexity of their type system. In Julia, is would not expect an essential technical challenge, because of its light-weight type system.
My understanding of abstract types in Julia, is
- they specify the programmer’s intention to support a certain set of functions (interface, contract, trait).
- they are used to select the method implementation according to argument types (method dispatch)
So, for bullet one, I do not see, why a programmer shouldn’t declare to support several traits.
For dispatching, currently, each type has a chain of direct supertypes, ending at Any
. The dispatching algorithm has to find the method implementation, which is most specific for all its arguments. A subtype is more specific than its supertype. Therefore implementations of methods for abstract types at the Any
- end of the chain can be hidden by others.
The situation does not change dramatically, if each type would have more than one direct supertype, generating a tree of supertypes instead of the chain. A possible solution with no impact to the dispatching algorithm would be linearisation of the tree. That means convert it into a linear list using a canonical algorithm. Best example I know for that is used in ‘Scala’, a strictly typed compiled language without multiple inheritance, with Trait
s, generating code for the JVM.