Skip to content

Add a leaf-name param accessor (getparam) to remove the dotted-key footgun #12

Closed

Description

@sotashimozono

Problem

DataKey.params is keyed by the dotted group.leaf path, so a work_fn must
write key.params["system.N"]. The plain leaf key.params["N"] silently raises
KeyError. This is the single most common point of confusion when writing a
work_fn (and a frequent mistake for code-generating assistants): the dotted
form is implicit — it comes from the [paramsets.system] table nesting, not
from anything the user typed literally — so the natural guess params["N"] is
wrong with no hint as to why.

Proposed enhancement

Add a core accessor that resolves an unambiguous leaf name and reuses the
existing AmbiguousPathKeyError machinery, so the dotted form keeps working
unchanged but the leaf form is also supported and fails loudly:

"""
    getparam(key::DataKey, pk) -> value

Look up `pk` in `key.params`, accepting either an exact key ("system.N" or a
top-level "N") or an unambiguous leaf name ("N" matching "system.N").
Throws AmbiguousPathKeyError if the leaf appears in multiple groups.
"""
function getparam(key::DataKey, pk::AbstractString)
    haskey(key.params, pk) && return key.params[pk]
    matches = [(k, v) for (k, v) in key.params if _split_dotted(k)[2] == pk]
    isempty(matches) && throw(KeyError(pk))
    length(matches) > 1 &&
        throw(AmbiguousPathKeyError(String(pk),
                                    sort([_split_dotted(m[1])[1] for m in matches])))
    return matches[1][2]
end

getparam(key, "N") then works whether the config wrote system.N or a
top-level N, and on a genuine collision (system.N and model.N) it raises
the same actionable error format_path/resolve_path_keys already use, instead
of a silent KeyError.

Use case

Every work_fn in apps/ReducedEnvExperiments.jl indexes params["system.N"],
params["system.chi"], params["strategy.name"], … A leaf accessor removes the
need to memorize the group prefix and converts the most common silent failure
into either a correct lookup or an explicit, fixable error. (Mirrors the
leaf-resolution format_path already does internally.)

Activity

  1. sotashimozono commented on Sep 15, 2026

    @sotashimozono
    MemberAuthor

    Already implemented, as param rather than getparam (#33, closing #32, merged 2026-09-08).

    src/core/param.jl + src/util/resolve.jl give exactly the resolution rule proposed here: exact match on the dotted name, else a unique match on the leaf, and AmbiguousPathKeyError naming the groups when the leaf sits in more than one.

    param(key, "system.N")   # exact
    param(key, "N")          # leaf, when unambiguous
    param(key, "N")          # AmbiguousPathKeyError("N", ["model", "system"]) when not

    Two things the shipped version has that this proposal did not:

    • param(key, name, T) converts and then, for numbers, checks the value survived the conversion; convert alone silently rounds Float32 from 2.1. That covers the other half of the Float64(key.params["system.kbT"]) idiom this issue was about.
    • the rule lives in one place (_resolve_name) with _lookup_name underneath it, so a caller that treats absent and ambiguous as ordinary outcomes does not reach them through a catch.

    Closing as implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions