Search code examples
typesjuliasupertype

Why create an abstract super type in Julia?


I am looking at someone code and it uses <: when creating a struct. I looked in the docs and found out that this means they are creating an abstract supertype. Can anyone explain what this is and why one would want to use it?


Solution

  • What are abstract types?

    Abstract types are nodes in the type hierarchy: they group types together. This allows you to write methods that apply to the whole group of types:

    julia> abstract type AbstractFoo end
    
    julia> struct Foo1 <: AbstractFoo end
    
    julia> struct Foo2 <: AbstractFoo end
    
    julia> foo_op(x::AbstractFoo) = "yay!"
    foo_op (generic function with 1 method)
    
    julia> foo_op(Foo1())
    "yay!"
    
    julia> foo_op(Foo2())
    "yay!"
    

    Why are abstract types useful?

    Abstract types allow you to separate behavior from implementation. This is critical for performance. When you declare an abstract supertype, you automatically inherit the core behavior of the supertype, but are free to implement more efficient implementations of that behavior.

    A common example is the AbstractArray abstract type. It represents the ability to access individual elements of some multi-dimensional collection of elements. Given some problem, we can usually choose a subtype of abstract arrays which will yield efficient operations: the additional constraints on a subtype constitute information that the programmer can leverage to make certain operations more efficient.

    For example, say we want to find the sum of 1..N. We could use an array of integers, but this would be very inefficient compared to a UnitRange. The choice of UnitRange encodes information about the characteristics of the data; information we can leverage for efficiency. (See this answer for more information on this example).

    julia> using BenchmarkTools
    
    julia> @btime sum($(1:1000_000))
      0.012 ns (0 allocations: 0 bytes)
    500000500000
    
    julia> @btime sum($(collect(1:1000_000)))
      229.979 μs (0 allocations: 0 bytes)
    500000500000
    

    BitArray provides space efficient representations for an array of booleans, SparseArrays provides efficient operations for sparse data, and so on. If you have some data that generally behaves like an abstract array, but has unique characteristics, you can define your own subtype.

    This pattern generalizes to other abstract types. Use them to group different implementations of some shared behavior.