### Immutable Structs Example Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Demonstrates the creation and behavior of immutable structs, where fields cannot be modified after initialization. ```julia @with_kw struct ImmutableType x::Int = 5 y::Int = 10 end obj = ImmutableType() # obj.x = 20 # ERROR - cannot assign to immutable object ``` -------------------------------- ### Mutable Structs Example Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Illustrates the creation and behavior of mutable structs, where fields can be modified in-place after initialization. ```julia @with_kw mutable struct MutableType x::Int = 5 y::Int = 10 end obj = MutableType() obj.x = 20 # Allowed - mutable object ``` -------------------------------- ### Function Using Type-Specific Unpack and Pack Macros Source: https://github.com/mauro3/parameters.jl/blob/master/docs/src/manual.md An example function demonstrating the use of automatically generated type-specific @unpack_* and @pack_*! macros for handling struct fields. ```julia function fn(var, pa::Para) # The macro is constructed during the @with_kw # and called @unpack_*: @unpack_Para pa out = var + a + b b = 77 @pack_Para! pa # only works with mutables return out, pa end out, pa = fn(7, pa) ``` -------------------------------- ### Ensuring Valid Type Definition Syntax Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Provides examples of correct struct syntax when using @with_kw. This helps resolve errors related to malformed type definitions. ```julia using Parameters # Make sure it's valid struct syntax @with_kw struct MyType{T<:Real} field::T = 1.0 end # Check for typos @with_kw struct MyType field::Int = 5 end ``` -------------------------------- ### Generated Constructors for @with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/api-reference.md Provides examples of the constructors automatically generated by the @with_kw macro for a generic struct `MM{R}`. This includes inner positional, inner keyword, outer positional, outer keyword, and copy constructors. ```julia # Inner positional constructor MM{R}(r, a) where {R} = new{R}(r, a) # Inner keyword constructor MM{R}(; r=1000.0, a=error("Field 'a' has no default...")) where {R} = MM{R}(r, a) # Outer positional constructor (only if type parameters used in fields) MM(r::R, a::R) where {R} = MM{R}(r, a) # Outer keyword constructor (only if type parameters used) MM(; r=1000.0, a=error("Field 'a' has no default...")) = MM(r, a) # Copy constructor MM(pp::MM; kws...) = reconstruct(pp, kws) MM(pp::MM, di::AbstractDict) = reconstruct(pp, di) MM(pp::MM, di::Vararg{Tuple{Symbol,Any}}) = reconstruct(pp, di) ``` -------------------------------- ### Reconstruct with Dict or Tuple Input Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/types.md Provides an example of using the reconstruct function with different input forms for field updates: a Dict and a tuple of symbol-value pairs. Both methods achieve the same result. ```julia struct A a b end x = A(1, 2) # Using Dict dict_form = Dict(:a => 10, :b => 20) y1 = reconstruct(x, dict_form) # Using tuple pairs pair_form = (:a => 10, :b => 20) y2 = reconstruct(x, pair_form) # Both result in A(10, 20) ``` -------------------------------- ### Copy Constructor Configuration Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Automatic copy constructors allow creating new instances from existing ones with optional field overrides. The example demonstrates copying a struct and modifying a field. ```julia struct MyType a::Int = 5 b::Float64 end original = MyType(b=10.0) # Copy with field modification: modified = MyType(original; a=20) # Same as: MyType(a=20, b=10.0) ``` -------------------------------- ### Keyword Constructor Defaults Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Define structs with default values for fields, allowing optional keyword arguments during instantiation. Field 'a' uses its default value, while 'a' is overridden in the second example. Type parameters can also be explicitly specified. ```julia struct MyType a::Int = 5 b::Int end # Field 'a' uses default: obj1 = MyType(b=10) # Field 'a' overridden: obj2 = MyType(a=20, b=10) # Type parameter explicitly specified: struct Param{T} value::T = 1.0 end obj3 = Param{Int}(value=5) ``` -------------------------------- ### Basic Keyword Defaults: Base.@kwdef vs. Parameters.@with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Illustrates the minimal syntax of Julia's built-in Base.@kwdef for simple defaults versus the more feature-rich @with_kw from Parameters.jl. ```julia # Base.@kwdef (minimal, built-in) Base.@kwdef struct Simple a::Int = 5 end # Parameters.jl (more features) @with_kw struct Featured a::Int = 5 end ``` -------------------------------- ### Define Versioned Configurations Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Shows how to manage evolving configurations by defining new versions of structs. Demonstrates migrating from an older version to a newer one by explicitly copying fields. ```julia @with_kw struct ConfigV1 learning_rate::Float64 = 0.01 momentum::Float64 = 0.9 end # Later, add new field with default @with_kw struct ConfigV2 learning_rate::Float64 = 0.01 momentum::Float64 = 0.9 weight_decay::Float64 = 0.0001 end # Migration v1_config = ConfigV1() v2_config = ConfigV2( learning_rate=v1_config.learning_rate, momentum=v1_config.momentum ) ``` -------------------------------- ### Custom Show Method: @with_kw vs. @with_kw_noshow Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Demonstrates the difference in display formatting between @with_kw, which provides a custom 'show' method for pretty printing, and @with_kw_noshow, which uses the default Julia representation. ```julia # Shows nice format @with_kw struct Type1 a::Int = 5 b::String = "test" end t1 = Type1() # Output: # Type1 # a: 5 # b: test # Shows default format @with_kw_noshow struct Type2 a::Int = 5 b::String = "test" end t2 = Type2() # Output: Type2(5, "test") ``` -------------------------------- ### Positional Constructor Configuration Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Generated positional constructors can be used, which bypass default values. This is preferred in performance-critical code. The example shows both keyword and positional instantiation. ```julia struct MyType a::Int = 5 b::Float64 c::String end # Keyword constructor: obj1 = MyType(b=10.0, c="test") # Positional constructor (bypasses defaults): obj2 = MyType(5, 10.0, "test") ``` -------------------------------- ### Assertion Configuration: @assert vs. @smart_assert Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Illustrates how to configure assertions during struct construction using either the standard `@assert` macro or the enhanced `@smart_assert` from SmartAsserts.jl for better error messages. Both execute at construction time. ```julia # Using standard @assert: @with_kw struct Type1 a::Int = 5 @assert a > 0 end # Using SmartAsserts.jl (better error messages): @with_kw struct Type2 a::Int = 5 @smart_assert a > 0 end ``` -------------------------------- ### Construct instances of a struct with default and non-default values Source: https://github.com/mauro3/parameters.jl/blob/master/docs/src/manual.md Demonstrates creating instances of a struct defined with `@with_kw`. You can use all defaults, specify the type parameter, provide some keyword arguments, or modify an existing instance. ```julia # Create an instance with the defaults pp = PhysicalPara() pp_f32 = PhysicalPara{Float32}() # the type parameter can be chosen explicitly # Make one with some non-defaults pp2 = PhysicalPara(cw = 77.0, day = 987.0) # Make another one based on the previous one with some modifications pp3 = PhysicalPara(pp2; cw = .11e-7, rw = 100.0) # the normal positional constructor can also be used # (and should be used in hot inner loops) pp4 = PhysicalPara(1, 2, 3, 4, 5, 6) ``` -------------------------------- ### Construct Object Using Keyword Arguments Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/INDEX.md Create an instance of a type by specifying field names and their corresponding values. ```julia # Keyword obj = Type(field=value) ``` -------------------------------- ### Julia: Valid inner constructor for @with_kw type Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md Provides an example of a valid custom inner constructor for a @with_kw type, which must accept at least one positional argument. ```julia struct MyType a::Int = 5 b::Int = 4 # This IS allowed - has positional arguments: MyType(a, b) where {} = (@assert a > b; new(a, b)) end ``` -------------------------------- ### Initialize OrderedDict for Keyword Arguments Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/types.md Illustrates initializing an OrderedDict to maintain the order of keyword arguments, as used internally by the @with_kw macro. ```julia kws = OrderedDict{Any,Any}() # Preserves definition order ``` -------------------------------- ### Unpack Parameters with UnPack.jl Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Demonstrates how to unpack fields from a Parameters struct using both the generic @unpack macro from UnPack.jl and the type-specific @unpack_Parameters macro generated by @with_kw. ```julia using Parameters using UnPack @with_kw struct Parameters a::Int = 1 b::Int = 2 c::Int = 3 end params = Parameters() # Generic @unpack from UnPack.jl @unpack a, c = params # Type-specific @unpack generated by @with_kw @unpack_Parameters params ``` -------------------------------- ### Complex Interdependencies in PhysicsSystem Struct Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Define a struct with multiple fields that have interdependencies and constraints. This example shows how `kinetic_energy`, `potential_energy`, and `total_energy` are computed based on `mass` and `velocity`, with assertions to ensure physical validity. ```julia @with_kw struct PhysicsSystem{T<:Real} mass::T = 1.0 @assert mass > 0 velocity::T = 0.0 kinetic_energy::T = mass * velocity^2 / 2 @assert kinetic_energy >= 0 potential_energy::T = 0.0 @assert potential_energy >= 0 total_energy::T = kinetic_energy + potential_energy end ``` -------------------------------- ### Manual Show Override Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Illustrates how to manually define a custom show method for a struct, allowing for a specific display format. ```julia @with_kw struct Data values::Vector{Float64} = [1.0, 2.0] metadata::Dict = Dict() # Provide custom show show_custom() = "Data with $(length(values)) values" end ``` -------------------------------- ### Simulating Optional Fields with Default Values Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Shows three methods to handle fields that should be optional: using `nothing` as a default, using a sentinel value, or defining multiple constructors. ```julia # Option 1: Use nothing as default @with_kw struct Type1 value::Union{Int, Nothing} = nothing end t = Type1() if t.value !== nothing println(t.value) end # Option 2: Default to a sentinel value @with_kw struct Type2 value::Int = -1 # -1 means "not set" end # Option 3: Multiple constructors @with_kw struct Type3 value::Union{String, Nothing} = nothing end Type3() = Type3(value=nothing) Type3(v::String) = Type3(value=v) ``` -------------------------------- ### Using Positional Constructor in Loops Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Compares the performance of creating struct instances within a loop. Demonstrates that using the positional constructor (implicitly when arguments match field order) is faster than explicitly naming fields. ```julia @with_kw struct Data values::Vector{Int} = [1, 2, 3] end # Slow slow = [Data(values=rand(0:10, 3)) for _ in 1:10000] # Fast fast = [Data(rand(0:10, 3)) for _ in 1:10000] ``` -------------------------------- ### Custom Show Method for Structs Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Demonstrates the default custom show method provided by `@with_kw` for structs, which uses `dump` for a detailed representation. ```julia @with_kw struct Employee name::String = "John" age::Int = 30 department::String = "Engineering" end emp = Employee() println(emp) ``` -------------------------------- ### Immutable vs. Mutable Structs with Parameters.jl Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Demonstrates how to handle immutable structs using `reconstruct` and mutable structs using `@pack!` for updates. ```julia # Immutable - must use reconstruct @with_kw struct Immutable x::Int = 5 y::Int = 10 end obj = Immutable() @unpack x, y = obj x = 20 obj = reconstruct(obj, x=x) # Creates new instance # Mutable - can use @pack! @with_kw mutable struct Mutable x::Int = 5 y::Int = 10 end obj = Mutable() @unpack x, y = obj x = 20 @pack! obj = x # Modifies in-place ``` -------------------------------- ### Global Default Configuration with Overrides Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Define default configuration values at the module level using `@with_kw`. This pattern allows for easy use of defaults and provides a clear way to override specific settings when calling functions. ```julia # Define default configuration at module level const DEFAULT_CONFIG = @with_kw ( debug = false, log_level = "info", cache_size = 100, timeout = 30.0, ) # Use with optional override function process_data(data; config=DEFAULT_CONFIG()) @unpack debug, timeout = config # ... end # Call with defaults result1 = process_data([1, 2, 3]) # Call with custom config custom = DEFAULT_CONFIG(debug=true, log_level="debug") result2 = process_data([1, 2, 3]; config=custom) ``` -------------------------------- ### Convenience Constructors for Matrix3x3 Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Create convenience constructors for a struct to simplify common initialization patterns. `Matrix3x3{T}()` creates an identity matrix, and `Matrix3x3_diag(d1, d2, d3)` creates a diagonal matrix. ```julia @with_kw struct Matrix3x3{T} m11::T = 1; m12::T = 0; m13::T = 0 m21::T = 0; m22::T = 1; m23::T = 0 m31::T = 0; m32::T = 0; m33::T = 1 end # Identity matrix constructor Matrix3x3{T}() where {T} = Matrix3x3{T}() # Diagonal matrix constructor Matrix3x3_diag(d1, d2, d3) = Matrix3x3(m11=d1, m22=d2, m33=d3) ``` -------------------------------- ### Documenting Struct Fields Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Use string literals before fields to document them. Access documentation using REPL.fielddoc. ```julia @with_kw struct Documented "The primary value" x::Int = 5 "The secondary value, defaults to 2*x" y::Int = 10 "A description" name::String = "default" end # Access in REPL REPL.fielddoc(Documented, :x) # "The primary value" REPL.fielddoc(Documented, :y) # "The secondary value, defaults to 2*x Default: 10" ``` -------------------------------- ### Define Configuration Object with Defaults Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/overview.md Use `@with_kw` to define a struct with default values and a keyword constructor. Useful for creating configuration objects. ```julia @with_kw struct Config debug::Bool = false max_iterations::Int = 1000 tolerance::Float64 = 1e-6 output_dir::String = "./output" end config = Config() config_debug = Config(debug=true) ``` -------------------------------- ### Test Default Parameter Values Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Illustrates how to test the default values of fields in a Config struct using assertions. This ensures that parameters are initialized correctly when no explicit values are provided. ```julia using Parameters using Test @with_kw struct Config debug::Bool = false timeout::Int = 30 end @test Config().debug == false @test Config().timeout == 30 @test Config(debug=true).debug == true ``` -------------------------------- ### Julia: Using an outer constructor for @with_kw type Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md Demonstrates how to define a custom constructor for a @with_kw type using an outer constructor to avoid conflicts with the generated zero-argument keyword constructor. ```julia struct MyType a::Int = 5 b::Int = 4 end # Outer constructor - no conflict MyType(a) = MyType(a, a-1) ``` -------------------------------- ### Construct and use a named tuple with default values Source: https://github.com/mauro3/parameters.jl/blob/master/docs/src/manual.md Demonstrates constructing a named tuple using the macro-generated constructor, overriding some defaults, and unpacking its values. ```julia julia> MyNT(f = x -> x^2, z = :foo) (f = #12, y = 3, z = :foo) julia> MyNT(f = "x -> x^3") (f = "x -> x^3", y = 3, z = "foo") julia> @unpack f, y, z = MyNT() (f = #7, y = 3, z = "foo") julia> f (::#7) (generic function with 1 method) julia> y 3 julia> z "foo" ``` -------------------------------- ### State Management: Immutable vs. Mutable Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Illustrates state management in Julia using both immutable and mutable structs. Immutable state is updated by creating new instances, while mutable state is modified in place. ```julia @with_kw struct AppState running::Bool = false request_count::Int = 0 active_connections::Int = 0 end @with_kw mutable struct MutableAppState running::Bool = false request_count::Int = 0 active_connections::Int = 0 end # Immutable - create new state for each change state = AppState() state = reconstruct(state; running=true) state = reconstruct(state; request_count=state.request_count + 1) # Mutable - modify in place state_mut = MutableAppState() state_mut.running = true state_mut.request_count += 1 ``` -------------------------------- ### Hot Path Optimization: Positional vs. Keyword Constructor Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Demonstrates performance differences between positional and keyword constructors for a struct. Positional constructors are recommended for hot loops due to Julia's current keyword performance. ```julia @with_kw struct Matrix{ T} data::Vector{T} rows::Int cols::Int end # Slow - keyword constructor function create_matrix_slow(n) [Matrix(data=rand(n), rows=n, cols=n) for _ in 1:1000] end # Fast - positional constructor function create_matrix_fast(n) [Matrix(rand(n), n, n) for _ in 1:1000] end ``` -------------------------------- ### Using Valid Field Names for Reconstruction Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Illustrates how to correctly use the `reconstruct` function by providing only valid field names that exist in the target type. Attempting to reconstruct with non-existent fields will result in an error. ```julia using Parameters struct MyType a b end x = MyType(1, 2) # Wrong - 'c' doesn't exist # y = reconstruct(x, c=3) # ERROR # Correct y = reconstruct(x, a=10) ``` -------------------------------- ### Flexible Defaults for Model Configurations Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Define a base template struct with default values for model parameters. This pattern allows for creating predefined configurations (like 'base', 'large', 'small') and custom configurations easily. ```julia # Create a "template" type @with_kw struct ModelTemplate architecture::String = "transformer" hidden_dim::Int = 768 num_layers::Int = 12 dropout::Float64 = 0.1 end # Predefined configurations const MODELS = ( base=ModelTemplate(), large=ModelTemplate(hidden_dim=1024, num_layers=24), small=ModelTemplate(hidden_dim=256, num_layers=6), custom(hidden_dim, num_layers) = ModelTemplate(hidden_dim=hidden_dim, num_layers=num_layers) ) # Use model_base = MODELS.base model_large = MODELS.large model_custom = MODELS.custom(512, 8) ``` -------------------------------- ### Unpacking Key-Value Pairs from a Dictionary Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/api-reference.md Shows how to unpack specific keys 'x' and 'z' from a dictionary 'd' into local variables. This is useful for extracting configuration or data from dictionary-like structures. ```julia d = Dict(:x => 10, :y => 20, :z => 30) @unpack x, z = d # x is now 10, z is now 30 ``` -------------------------------- ### Compare Keyword vs. Positional Constructor Performance Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/overview.md Illustrates the performance difference between keyword and positional constructors for the Particle struct. The positional constructor is recommended for performance-critical code. ```julia # Slow - keyword constructor function create_slow(n::Int) particles = [Particle(position=rand(3), velocity=rand(3)) for _ in 1:n] end # Fast - positional constructor function create_fast(n::Int) particles = [Particle(rand(3), rand(3), 1.0) for _ in 1:n] end ``` -------------------------------- ### Define and Use Execution Context Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Illustrates how to define a struct for execution context and pass it through computations. Useful for managing shared state like thread IDs, user IDs, and trace IDs. ```julia @with_kw struct ExecutionContext thread_id::Int user_id::String trace_id::String start_time::Float64 timeout::Float64 = 60.0 metadata::Dict = Dict() end function execute_with_context(user_id::String, f::Function) ctx = ExecutionContext( thread_id=Threads.threadid(), user_id=user_id, trace_id=uuid4(), start_time=time() ) # Pass context through computation result = f(ctx) return result end # Inside computation function compute(ctx::ExecutionContext) @unpack user_id, trace_id, timeout = ctx # Use context variables # ... end ``` -------------------------------- ### Manage Optional Features with Flags Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Demonstrates how to use a FeatureFlags struct to control optional features and their modes. Useful for enabling/disabling features or configuring their behavior across different environments. ```julia @with_kw struct FeatureFlags feature_a_enabled::Bool = false feature_b_enabled::Bool = false feature_c_enabled::Bool = false feature_c_mode::String = "basic" # "basic" or "advanced" end function handle_request(data, flags::FeatureFlags) @unpack feature_a_enabled, feature_b_enabled, feature_c_enabled, feature_c_mode = flags if feature_a_enabled # Use feature A end if feature_b_enabled # Use feature B end if feature_c_enabled if feature_c_mode == "advanced" # Advanced feature C else # Basic feature C end end end # Different configurations for different deployments flags_dev = FeatureFlags( feature_a_enabled=true, feature_b_enabled=true, feature_c_enabled=true, feature_c_mode="advanced" ) flags_prod = FeatureFlags( feature_a_enabled=true, feature_c_enabled=true, feature_c_mode="basic" ) ``` -------------------------------- ### Create New Instance by Packing All Fields Source: https://github.com/mauro3/parameters.jl/blob/master/docs/src/manual.md Generates a new instance of a struct by packing all its fields using a type-specific macro (e.g., @pack_Para). This is intended for immutable types. ```julia pa2 = @pack_Para ``` -------------------------------- ### Documenting Struct Types Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Add a multi-line string before the struct definition for type documentation. Access using the @doc macro. ```julia "A type for storing geometric measurements. # Fields - width: The width in arbitrary units - height: The height in arbitrary units " @with_kw struct Geometry width::Float64 = 1.0 height::Float64 = 1.0 end # Access docstring @doc Geometry ``` -------------------------------- ### Testing Copy Constructors Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Verify copy constructors by creating an original object and then creating copies, both shallow and with modifications. Ensure specific fields are copied or updated as expected. ```julia using Test using Parameters # Assume Config struct is defined as above, potentially with debug and port fields # @with_kw struct Config # min_val::Int = 0 # max_val::Int = 100 # debug::Bool = false # port::Int = 80 # @assert min_val < max_val # end @testset "copy constructor" begin # Assuming Config has debug and port fields # orig = Config(debug=true, port=3000) # copy1 = Config(orig) # @test copy1.debug == true # @test copy1.port == 3000 # copy2 = Config(orig; debug=false) # @test copy2.debug == false # @test copy2.port == 3000 # Unchanged end ``` -------------------------------- ### Define Struct with Keyword Constructor and Defaults Source: https://github.com/mauro3/parameters.jl/blob/master/README.md Use the `@with_kw` macro to define a struct that allows keyword arguments for its constructor and supports default values for fields. Fields without defaults must be provided. ```julia using Parameters @with_kw struct A a::Int = 6 b::Float64 = -1.1 c::UInt8 end A(c=4) A() A(c=4, a = 2) ``` -------------------------------- ### Define Basic Keyword Struct Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/INDEX.md Define a struct with keyword arguments and default values. Fields are automatically initialized. ```julia # Basic @with_kw struct Type field::Type = default end ``` -------------------------------- ### Resolving TypeErrors by Matching Field Types Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md Shows the correct way to instantiate `MyType` by ensuring the assigned values match the declared types. This involves either adjusting the type parameter `R` to accommodate the value or ensuring the value itself conforms to the expected type. ```julia x = MyType{Float64}(a=5.5, b=10) # a is now Float64 # or x = MyType{Int}(a=5, b=10) # a is Int ``` -------------------------------- ### Optimizing Constructor Performance in Loops Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Compares the performance of keyword constructors versus positional constructors within loops. Positional constructors are generally faster for performance-critical code. ```julia using Parameters @with_kw struct Vector3 x::Float64 = 0.0 y::Float64 = 0.0 z::Float64 = 0.0 end # Slow slow = [Vector3(x=rand(), y=rand(), z=rand()) for _ in 1:10000] # Fast fast = [Vector3(rand(), rand(), rand()) for _ in 1:10000] ``` -------------------------------- ### Performance Comparison: Keyword vs. Positional Constructors Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Highlights that for performance-critical code, using the standard positional constructor for structs is significantly faster than the keyword constructor generated by @with_kw due to reduced allocations. ```julia @with_kw struct Particle x::Float64 = 0.0 y::Float64 = 0.0 z::Float64 = 0.0 end # Slow - keyword constructor (generates many allocations) function create_slow(n) [Particle(x=rand(), y=rand(), z=rand()) for _ in 1:n] end # Fast - positional constructor function create_fast(n) [Particle(rand(), rand(), rand()) for _ in 1:n] end ``` -------------------------------- ### Creating Struct Variations with Copy Constructors Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Shows how to create new instances of a struct with modified fields without altering the original instance, using a copy constructor pattern. ```julia @with_kw struct Settings theme::String = "light" font_size::Int = 12 auto_save::Bool = true language::String = "en" end user_settings = Settings() # Create variations without modifying original dark_settings = Settings(user_settings; theme="dark") large_font_settings = Settings(user_settings; font_size=16) no_autosave = Settings(user_settings; auto_save=false) # Original unchanged println(user_settings.theme) # "light" ``` -------------------------------- ### Handling Default Values with External Functions in Parameters.jl Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Illustrates the correct way to define default field values that depend on external functions by using `nothing` or sentinel values and computing lazily. ```julia # Wrong - might not work @with_kw struct Type1 data::Vector = external_function() # Might not be available end # Correct - use nothing @with_kw struct Type1 data::Vector = [] # Use simple default end # Or use default value from input function create_type(data=nothing) if data === nothing data = external_function() end Type1(data=data) end ``` -------------------------------- ### Lazy Field Initialization Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Defer expensive computations for fields until they are actually needed, improving initial object creation time. ```julia @with_kw struct LazyType value::Int = 5 expensive_field::Any = nothing # None initially function compute_expensive() if expensive_field === nothing expensive_field = # ... expensive computation ... end return expensive_field end end ``` -------------------------------- ### Ensuring Custom Show Method Usage with Parameters.jl Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Verify that your custom `show` method is being used by checking for `@with_kw` (not `_noshow`) and confirming no other `show` methods are defined for the type. ```julia # This defines custom show @with_kw struct MyType a::Int = 5 end # Check if another show method exists methods(show, (IO, MyType)) # Should show the custom one # If not, verify @with_kw was used ``` -------------------------------- ### Define Configuration with Interdependent Parameters Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Create a configuration struct where some fields depend on others, allowing for computed values. Changes to dependent fields automatically update the computed fields. ```julia @with_kw struct ProcessConfig num_workers::Int = 4 batch_size::Int = 32 queue_size::Int = num_workers * batch_size # Depends on workers timeout::Float64 = 30.0 max_retries::Int = 3 retry_delay::Float64 = timeout / max_retries # Computed end # Basic config cfg1 = ProcessConfig() println(cfg1.queue_size) # 128 (4 * 32) # Custom workers changes queue size cfg2 = ProcessConfig(num_workers=8) println(cfg2.queue_size) # 256 (8 * 32) ``` -------------------------------- ### Macros Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/INDEX.md Parameters.jl provides several macros to simplify the definition and manipulation of types with keyword constructors, default values, and unpacking capabilities. ```APIDOC ## Macros ### `@with_kw` **Description**: Defines a type with default keyword arguments and a custom keyword constructor. ### `@with_kw_noshow` **Description**: Similar to `@with_kw` but omits the custom show method. ### `@unpack` **Description**: Extracts fields from a type instance into local variables. ### `@pack!` **Description**: Packs local variables back into a mutable type instance. ### `@consts` **Description**: Defines multiple constants within a scope. ``` -------------------------------- ### Access and Unpack NamedTuple Fields Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Demonstrates how to access fields of a NamedTuple by dot notation or index, and how to unpack fields into local variables using the @unpack macro. ```julia MyNT = @with_kw (x=1, y=2, z=3,) # Note trailing comma for single field nt = MyNT() nt.x # 1 nt[1] # 1 nt.y # 2 # Unpacking @unpack x, z = nt # x=1, z=3 ``` -------------------------------- ### Define Struct with Keyword Constructor (No Show Method) Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/api-reference.md Use `@with_kw_noshow` to define a struct that supports keyword arguments in its constructor but does not override the default `show` method. This is useful to prevent 'method redefinition' warnings when redefining types. ```julia @with_kw_noshow struct MT2 r::Int = 5 c::Any a::Float64 end # Prints using default method representation mt = MT2(r=4, a=5.0, c="test") println(mt) ``` -------------------------------- ### Struct with Field Documentation using @with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Add documentation strings to fields within a struct definition using the @with_kw macro. ```julia @with_kw struct MyType "Documentation for this field" field1::Int = 5 "Another field" field2::Float64 end ``` -------------------------------- ### Type Parameter Inference with Parameters.jl Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Explains how type parameter inference works and how to ensure it functions correctly by using type parameters in field types. ```julia # Works - T is used in field type @with_kw struct Good{T} data::T count::Int = 0 end g = Good(data=[1, 2, 3]) # T inferred as Vector{Int} # Doesn't work - T not used in fields @with_kw struct Bad{T} count::Int = 0 name::String = "default" end # Can't infer T - must specify explicitly b = Bad{String}(count=5) ``` -------------------------------- ### Correct @with_kw Syntax for Structs and NamedTuples Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md Demonstrates the correct syntax for using the @with_kw macro with both struct definitions and NamedTuples, emphasizing the required space after the macro. ```julia # Structs @with_kw struct MyType # fields end # NamedTuples MyNT = @with_kw (x=1, y=2,) # Note trailing comma for single-field tuples ``` -------------------------------- ### type2dict Configuration Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md No configuration is needed for type2dict; it converts any struct to a dictionary. -------------------------------- ### Providing Required Fields in Keyword Constructors Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Shows how to handle required fields in structs defined with @with_kw. All fields without a default value must be supplied as keyword arguments during construction. ```julia using Parameters @with_kw struct MyType required_field::String # No default - REQUIRED optional_field::Int = 5 end # Wrong # obj = MyType() # ERROR - missing required_field # Correct obj = MyType(required_field="test") # Alternative: Add a default value @with_kw struct MyType field::String = "default" # Now has default end obj = MyType() # OK ``` -------------------------------- ### Correct NamedTuple Syntax with @with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Demonstrates the proper syntax for defining NamedTuples using the @with_kw macro, including the use of trailing commas for single-field tuples. ```julia using Parameters # Wrong - looks like function call # Config = @with_kw(a=1) # Correct - space and tuple syntax Config = @with_kw (a=1,) # Multiple fields don't need trailing comma Options = @with_kw (x=1, y=2) ``` -------------------------------- ### Preserving Field Documentation with Default Values Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Shows how documentation strings for fields are preserved and automatically augmented with their default values when using @with_kw. ```julia @with_kw struct Documented "The first value" a::Int = 5 "The second value" b::Float64 = 10.0 end REPL.fielddoc(Documented, :a) # Output: "The first value Default: 5" ``` -------------------------------- ### Define Model Parameters with Assertions for Constraints Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Define a struct for neural network configurations with constraints enforced using @assert. Invalid values will trigger an AssertionError during instantiation. ```julia @with_kw struct NeuralNetConfig layers::Int = 3 @assert layers >= 1 hidden_units::Int = 64 @assert hidden_units >= 8 learning_rate::Float64 = 1e-3 @assert learning_rate > 0 && learning_rate < 1 batch_size::Int = 32 @assert batch_size > 0 dropout::Float64 = 0.1 @assert dropout >= 0 && dropout <= 1 end # Valid configuration nn = NeuralNetConfig() # Invalid - will error # bad = NeuralNetConfig(learning_rate=1.5) # ERROR: AssertionError ``` -------------------------------- ### Checking Field Names with fieldnames() Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md Before attempting reconstruction, you can verify the available field names for a given type using the 'fieldnames()' function. ```julia fieldnames(A) # Returns (:a, :b) ``` -------------------------------- ### Struct with Field Assertions and Interdependence using @with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/api-reference.md Illustrates how to define fields with default values that depend on other fields, and how to create an instance where these dependencies are automatically resolved. Requires the field `b` to be provided. ```julia @with_kw struct Para{R<:Real} a::R = 5 b::R c::R = a + b end pa = Para(b=7) # c is automatically 12 ``` -------------------------------- ### Construct Object Using Positional Arguments Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/INDEX.md Create an instance of a type using positional arguments, following the order of field definition. ```julia # Positional obj = Type(value1, value2, value3) ``` -------------------------------- ### Forgetting Required Fields in Structs Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/faq-and-troubleshooting.md Demonstrates how to define a struct with a required field (no default value) and the error that occurs when it's omitted during instantiation. Shows the correct way to provide the required field. ```julia # Easy to forget what's required @with_kw struct Config debug::Bool = false level::String = "info" api_key::String # REQUIRED - no default end # Forgot api_key! config = Config() # ERROR # Remember to provide it config = Config(api_key="secret") ``` -------------------------------- ### Use NamedTuple Pattern for Configuration Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Utilize a NamedTuple with default settings as a module-level constant for function configurations. This promotes consistent and easily modifiable default parameters. ```julia # Module-level constant NamedTuple DefaultSettings = @with_kw ( max_workers = 4, memory_limit = 1024, cache_enabled = true, log_level = "info", ) # Use in functions function process(data, settings=DefaultSettings()) @unpack max_workers, cache_enabled = settings # ... end ``` -------------------------------- ### Test Copy Constructor with Parameter Overrides Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Shows how to test the copy constructor of a struct, verifying that parameters from an inner struct are correctly copied and that outer parameters can override them. ```julia using Parameters using Test @with_kw struct Config debug::Bool = false timeout::Int = 30 end @test Config(Config(debug=true); timeout=60).debug == true @test Config(Config(timeout=45); debug=false).timeout == 45 ``` -------------------------------- ### Alternative Constructors for Point Struct Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Implement alternative outer constructors for a struct to provide different ways of initializing instances. The `Point(x::T)` constructor initializes both x and y to `x`, while the `Point(p::Point{T}; scale=1)` constructor creates a scaled copy. ```julia @with_kw struct Point{T} x::T = 0 y::T = 0 end Point(x::T) where {T} = Point{T}(x=x, y=x) # Outer constructor Point(p::Point{T}; scale=1) where {T} = Point{T}(x=p.x*scale, y=p.y*scale) ``` -------------------------------- ### Import OrderedDict Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/types.md Shows the import statement required to use the OrderedDict type from the OrderedCollections.jl package. ```julia import OrderedCollections: OrderedDict ``` -------------------------------- ### Module Exports for Parameters.jl Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/overview.md Lists the main functions and macros exported by the Parameters.jl module. These are the primary tools for users to interact with the package's features. ```julia export @with_kw export @with_kw_noshow export type2dict export reconstruct export @unpack export @pack! export @consts ``` -------------------------------- ### Functions Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/INDEX.md Parameters.jl includes utility functions for converting between data structures and reconstructing type instances. ```APIDOC ## Functions ### `type2dict(instance)` **Description**: Converts a struct instance to a dictionary. **Parameters**: - `instance` (Any) - The struct instance to convert. ### `reconstruct(instance; kwargs...)` **Description**: Creates a modified copy of a type instance with specified keyword arguments. **Parameters**: - `instance` (Any) - The original type instance. - `kwargs...` - Keyword arguments to modify fields in the new instance. ``` -------------------------------- ### Packing Fields into Mutable Structs Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/advanced-features.md Demonstrates how to use `@pack!` to modify the fields of a mutable struct in-place using unpacked variables. ```julia @unpack x, y = obj x = 100 y = 200 @pack! obj = x, y # Modifies obj in-place ``` -------------------------------- ### Julia: Constructing @with_kw type without required field Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md Demonstrates the error when a required field (without a default) is not provided as a keyword argument during the construction of a @with_kw type. ```julia struct MyType a::Int = 5 # Has default b::Float64 # No default - REQUIRED end # This works: obj1 = MyType(b=10.0) # This fails with the error: obj2 = MyType() # ERROR: Field 'b' has no default, supply it with keyword. ``` -------------------------------- ### Equivalent Code for @consts Macro Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/api-reference.md This shows the direct translation of the @consts macro usage into standard Julia 'const' declarations. It illustrates how the macro simplifies the definition of multiple constants. ```julia const GRAVITY = 9.81 const PI = 3.14159 const SPEED_OF_LIGHT = 299792458 const NAME = "MyApp" ``` -------------------------------- ### Generated Macros for @with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/api-reference.md Demonstrates the unpacking and packing macros generated by @with_kw for a type named `MM`. These macros facilitate easy access to and modification of struct fields within local scope. ```julia # For a type named `MM`, the macro generates: # - `@unpack_MM(varname)`: Unpacks fields into local variables # - `@pack_MM!(varname)`: Packs local variables back (mutable types only) # - `@pack_MM()`: Constructs new instance from local variables function process(data, params::MM) @unpack_MM params # r and a now available as local vars result = data + r * a r = 100 packed = @pack_MM() # Create new MM with updated r return result, packed end ``` -------------------------------- ### ErrorException: No inner constructors with zero positional arguments plus keyword arguments allowed Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/errors.md This error occurs when a @with_kw type definition includes an inner constructor with zero positional arguments but accepts keyword arguments. Ensure inner constructors have at least one positional argument. ```julia @with_kw struct MyType a::Int = 5 # This is NOT allowed: MyType(; a=5) = new(a) end ``` ```julia @with_kw struct MyType a::Int = 5 b::Int = 4 # This IS allowed: MyType(a, b) where {} = new(a, b) end ``` -------------------------------- ### Selective Field Unpacking in a Function Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/examples-and-patterns.md Demonstrates unpacking only the necessary fields within a function to improve clarity and potentially performance. ```julia @with_kw struct Parameters a::Int = 1 b::Int = 2 c::Int = 3 d::Int = 4 e::Int = 5 end function process(p::Parameters) # Only unpack what we need @unpack a, c, e = p return a + c + e end result = process(Parameters()) # 1 + 3 + 5 = 9 ``` -------------------------------- ### Struct with Assertions using @with_kw Source: https://github.com/mauro3/parameters.jl/blob/master/_autodocs/configuration.md Include assertions to validate field values during struct initialization using the @with_kw macro. ```julia @with_kw struct MyType a::Int = 5 @assert a > 0 b::Float64 = 1.0 @assert b < 100.0 @assert a < b # Can reference multiple fields end ```