Wrapping kw-based Parameters.jl constructor, for deprecation

I have a config object like this:

using Parameters

@with_kw mutable struct Config
    "Param 1"
    param1::Float64

    # ... several other items ...

    "Whether to iterate randomly."
    use_random::Bool = false
end

And now I need to modify it like so, to enable more than 2 strategies:

@with_kw mutable struct Config
    "Param 1"
    param1::Float64

    # ... several other items ...

    "Strategy for iteration, one of 'random' or 'baseline'."
    iter_strategy::String = "random"
end

But this is a breaking change to its definition, so I want to give some deprecation help to the user.

Is there some way I can intercept existing calls to the keyword-based constructor generated by @with_kw, changing a use_random setting to the appropriate iter_strategy value, and issuing a warning that the caller should change their code? Existing callers would have code like Config(param1=1.1, use_random=true) or similar.

Thanks.

FYI this is very similar to Catching deprecated keyword arguments (with Parameters.jl), which doesn’t currently have an answer.

Not sure if that works for your non-MWE, but this is what I (got the ping from the linked post) ended up using:

@kwdef mutable struct Config
    """Param 1"""
    param1::Float64
    
    """Deprecated, please use `iter_strategy = "random"` instead."""
    use_random::Union{Bool, Nothing} = nothing
    
    """Strategy for iteration, one of `random` or `baseline`."""
    iter_strategy::String = (isnothing(use_random) || use_random) ? "random" : "baseline" 
end

Config(; param1 = 1.0, use_random = true)           # Config(1.0, true, "random")
Config(; param1 = 1.0, use_random = false)          # Config(1.0, false, "baseline")
Config(; param1 = 1.0)                              # Config(1.0, nothing, "random")
Config(; param1 = 1.0, iter_strategy = "baseline")  # Config(1.0, nothing, "baseline")
Config(; param1 = 1.0, iter_strategy = "random")    # Config(1.0, nothing, "random")

If you can live with the type change (and the union) as “non-breaking” for the outside, then this might be a “workaround”.

EDIT: You could of course make the default initialization more complex, e.g., catching and preventing that a user passes both arguments.

Yeah, I don’t love having the union of the fields in there, it creates some confusion in users of the Config object since both fields are still there. I’d prefer to take care of everything before/while creating the object and have no use_random field left.

FWIW I didn’t find a great solution to this at the constructor point, I ended up finding all the places in my code where a constructor is called and adjusting the calls there.

If there were a way to call the @with_kw-generated constructor from a new constructor, that would be a great way to fix this in one spot for all callers.