100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Custom Types and Structs

Learn how to define composite types with struct, control mutability and construction, use parametric fields for performance, and attach behavior via multiple dispatch.

Arrays & TypesIntermediate9 min readJul 10, 2026
Analogies

Defining Structs

A struct in Julia declares a new composite type with named, typed fields — for example, struct Point x::Float64; y::Float64 end defines a Point type with two Float64 fields. By default, structs are immutable: once a Point is constructed, its x and y fields cannot be reassigned, which lets the compiler store instances more efficiently (often directly on the stack or inline inside containers) and reason more confidently about the code. Julia automatically generates a default positional constructor, so Point(1.0, 2.0) works immediately without writing any constructor code yourself.

🏏

Cricket analogy: Defining struct Point x::Float64; y::Float64 end is like fixing a player's scorecard template to always have exactly two typed fields — runs and balls faced — before a single innings is recorded, giving the scorer a guaranteed structure to fill in.

Mutable Structs and Constructors

Prefixing the declaration with mutable struct allows fields to be reassigned after construction, at the cost of the extra indirection and allocation that heap-allocated, mutable objects require. Custom inner constructors — defined inside the struct body using the special new() function — let you validate or transform arguments before constructing the instance, for example rejecting a negative radius in a Circle struct; outer constructors, defined outside the struct body as ordinary methods, add convenience forms like a default constructor that fills in a missing field, without touching the type's core definition.

🏏

Cricket analogy: A mutable struct is like a live scoreboard display that gets updated ball by ball throughout an innings, unlike a printed final scorecard; the extra electronics and refresh mechanism (heap allocation) are the cost of allowing those in-place updates.

julia
struct Circle
    radius::Float64
    # inner constructor validates the argument before construction
    function Circle(radius::Float64)
        radius < 0 && throw(ArgumentError("radius must be non-negative"))
        new(radius)
    end
end

# outer constructor: convenience method accepting an Int
Circle(radius::Int) = Circle(Float64(radius))

area(c::Circle) = π * c.radius^2

c = Circle(2)         # uses the outer constructor, then the validating inner one
area(c)                # 12.566...

Parametric Types

Structs can be parameterized over types, as in struct Point{T} x::T; y::T end, letting a single definition serve Point{Int64}, Point{Float64}, or even Point{Rational{Int}} while keeping each field concretely typed for that instance. This matters for performance: a field declared as T (a type parameter bound to a concrete type at construction) lets the compiler generate specialized, unboxed machine code for each concrete instantiation, whereas a field declared with an abstract type like Real would force Julia to box every value and dispatch dynamically at each field access.

🏏

Cricket analogy: A parametric struct Point{T} is like a single scorecard template that works for both a T20 match (T = 20 overs) and a Test match (T = unlimited overs) — same structure, specialized per format, with each printed card being concretely one format, not a vague mix of both.

Prefer parametric fields (x::T) over abstract-typed fields (x::Real) whenever you control the struct definition — this is one of the single biggest, easiest performance wins in Julia because it lets the compiler generate specialized code per concrete type instead of falling back to boxed, dynamically dispatched field access.

Methods and Dispatch on Custom Types

Once a struct exists, you define behavior for it by writing ordinary functions whose argument types include that struct, such as area(c::Circle) = π * c.radius^2 — Julia's multiple dispatch then selects the most specific matching method at each call site based on the runtime types of all arguments, not just the first one as in classical single-dispatch object-oriented languages. This means you can later define area(r::Rectangle) or even overlap(c::Circle, r::Rectangle) as separate methods of the same generic function name, and Julia will route each call to the correct implementation automatically.

🏏

Cricket analogy: Multiple dispatch choosing overlap(c::Circle, r::Rectangle) based on both arguments is like an umpire's LBW decision depending on both the bowler's delivery type and the batsman's stance simultaneously, not just one factor in isolation — the ruling (method) is selected from the full combination.

Declaring a struct field with an abstract type, such as radius::Real instead of radius::Float64 (or a type parameter T), forces Julia to box the value and prevents the compiler from specializing field access — this is one of the most common accidental performance regressions in Julia code and shows up clearly as red 'Any' or abstract-type output in @code_warntype.

  • struct declares an immutable composite type by default; mutable struct allows field reassignment.
  • Julia auto-generates a positional constructor; inner constructors (using new()) add validation, outer constructors add convenience.
  • Parametric structs (struct Point{T} ... end) let one definition serve many concrete types efficiently.
  • Concretely-typed fields let the compiler generate specialized, unboxed code; abstract-typed fields force boxing.
  • Methods are defined outside the struct as ordinary functions dispatched on argument types.
  • Multiple dispatch selects a method based on the runtime types of ALL arguments, not just the first.
  • New methods for new types can be added later without modifying existing struct or method code.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#JuliaStudyNotes#CustomTypesAndStructs#Custom#Types#Structs#Defining#StudyNotes#SkillVeris#ExamPrep