Handling solver parameters elegantly in Julia

You were missing a ; when calling the Param keyword constructor. This now runs for me:

using Parameters: @with_kw
using NamedTuples

@with_kw struct Param
    mean     = 0.
    variance = 1.
end

struct Solver
    params::Dict{Symbol,Param}
end

function Solver(params...)
    # build Dict for inner ctor
    dict = Dict{Symbol,Param}()
    
    for (varname, varparams) in params
        # varparams is a NamedTuple
        d = Dict(k => v for (k,v) in zip(fieldnames(typeof(varparams)), varparams))
        
        push!(dict, varname => Param(; d...))
    end

    Solver(dict)
end

solver = Solver(
  :var1 => @NT(mean=1.),
  :var2 => @NT(variance=2)
)

Note that your lines above are still not an MWE, because GaussianVariogram is not defined, and variogram is not a field Param knows about. I of course modified it accordingly, but when you are asking for help with code, posting a self-contained MWE in a single post will get you replies much faster.

3 Likes

Thank you @Tamas_Papp, I always forget the ; before the kwargs, below is an even cleaner version:

function Solver(params...)
  dict = Dict{Symbol,Param}()

  for (varname, varparams) in params
    kwargs = [k => v for (k,v) in zip(keys(varparams), varparams)]
    push!(dict, varname => Param(; kwargs...))
  end

  Solver(dict)
end

@Tamas_Papp, regarding your previous comment about the inner constructor, I don’t know what is happening, but if I comment it out, I get a strange error:

MethodError: Cannot `convert` an object of type Pair{Symbol,NamedTuples._NT_variogram{GeoStats.GaussianVariogram{Float64,Float64,GeoStats.EuclideanDistance}}} to an object of type Dict{Symbol,GeoStats.KrigParam}
This may have arisen from a call to the constructor Dict{Symbol,GeoStats.KrigParam}(...),
since type constructors fall back to convert methods.

This is the line that I am commenting out: https://github.com/juliohm/GeoStats.jl/blob/master/src/solvers/kriging_solver.jl#L77