Skip to content

Types

Parametric types without the type parameter are NOT DataTypes; they are UnionAll.

Example: struct Foo{T} end; isa(Foo, DataType) == false;

I find it easiest to write model specific code NOT using parametric types. Instead, I define type aliases for the types used in custom types (e.g., Double=Float64). Then I hardwire the use of Double everywhere. This removes two problems:

  1. Possible type instability as the compiler tries to figure out the types of the custom type fields.
  2. It becomes possible to call constructors with, say, integers of all kinds without raising method errors.

Constructors (1.5)

Constructing objects with many fields:

  • Define an inner constructor that leaves the object (partially) uninitialized. It is legal to have new(x) even if the object contains additional fields.
  • LazyInitializedFields.jl ensures that accessing uninitialized fields gives errors.

Parameters.jl is useful for objects with default values.

  • Constructor must then provide all arguments that do not have defaults.
  • Note that @with_kw automatically defines show(). Use @with_kw_noshow to avoid this.
  • Base.@kwdef now does much of the same.

Inheritance (1.5)

There is no inheritance in Julia. Abstract types have no fields and concrete types have no subtypes.

There are various discussions about how to implement types that share common fields.

For simple cases, it is probably best to just repeat the fields in all types. This can be automated using @forward in Lazy.jl.

using Lazy
struct Foo
  x
end
@forward Foo.x (Base.show, Base.isempty)

One good piece of advice: ensure that methods are generally defined on the abstract type, so that all concrete types have the same interface (kind of the point of having an abstract type).

A macro that lets users define a set of common fields for a set of structs:

macro def(name, definition)
    return quote
        macro $(esc(name))()
            esc($(Expr(:quote, definition)))
        end
    end
end

@def commonfields begin
    #Data
    X #Feature vectors
    y #Labels (-1,1)
    nSamples::Int64 # Number of data points
    nFeatures::Int64 # Number of features
end

struct Foo
    @commonfields
    z
end

User Defined Types (1.5)

LazyInitializedFields.jl is a nice way of handling partially initialized struct fields.