Published March 31, 2026 | Version v0.3.0
Software Open

ModuleMixins.jl.jl

Authors/Creators

Description

ModuleMixins v0.3.0

Diff since v0.2.0

Changelog

  • No breaking changes.
  • Refactors code and tests into modules.
  • Adds major new feature: constructors.

Constructors

When you can use inheritance to compose larger objects, it would also be nice if we can construct the larger object without additional code. Suppose we have some Input and a State struct. It is good to put common definitions in a Common module.

using ModuleMixins

module Common
    using Unitful
    export @u_str, Seconds, Kilograms, Meters, Radians, RadiansPerSecond

    const Seconds = typeof(1.0u"s")
    const Kilograms = typeof(1.0u"kg")
    const Meters = typeof(1.0u"m")
    const Radians = typeof(1.0u"rad")
    const RadiansPerSecond = typeof(1.0u"rad/s")
end

Our very first component stores the Input inside the State for later reference:

@compose module ModelBase
    @kwdef struct Input
    end

    struct State{I}
        input::I
    end

    @constructor initial_state(input)::State[input] = (input = input,)
end

Notice that we must give the return type of the constructor, and the fields that the constructor initializes using a hand-crafted syntax State[input] here. A constructor must always return a NamedTuple with those same fields. All later additions to the constructor must have the same parameter names, in this case just input.

Our first real component introduces time:

@compose module Time
    @mixin ModelBase
    using ..Common

    @kwdef struct Input
        delta_t::Seconds = 0.1u"s"
        steps::Int = 1000
    end

    struct State
        step::Int
    end

    @constructor initial_state(input)::State[step] = (step = 0,)

    time(state) = state.step * state.input.delta_t
end

We may model a pendulum:

@compose module Pendulum
    using ..Common
    @mixin Time

    @kwdef struct Input
        length::Meters = 1.0u"m"
        mass::Kilograms = 1.0u"kg"
        initial_angle::Radians = 30.0u"deg"
    end

    struct State
        angle::Radians
        angular_velocity::RadiansPerSecond
    end

    @constructor function initial_state(input)::State[angle, angular_velocity]
        (angle = input.initial_angle,
         angular_velocity = 0.0u"rad/s")
    end
end

See here that both long and short-form function notation is supported. We can now create an initial state using the default values for input.

Pendulum.initial_state(Pendulum.Input())

Merged pull requests:

  • Bump codecov/codecov-action from 4 to 5 (#6) (@dependabot[bot])
  • Bump actions/checkout from 4 to 6 (#7) (@dependabot[bot])
  • Bump julia-actions/cache from 2 to 3 (#8) (@dependabot[bot])
  • Bump codecov/codecov-action from 5 to 6 (#9) (@dependabot[bot])
  • change syntax to make constructor return fields explicit; complete introduction; change example (#10) (@jhidding)

Notes

If you use this software, please cite it using the metadata from this file.

Files

jhidding/ModuleMixins.jl-v0.3.0.zip

Files (155.5 kB)

Name Size Download all
md5:17819c1b27a26b7810014bd111fb4c85
155.5 kB Preview Download

Additional details

Related works