property-dots
DevelopmentGuide for writing functions that accept property name-value pairs via `...`. Use when adding a function whose `...` collects property values.
How to use this skill
Bring this guide into your coding agent with a prompt tailored to the tool you use.
- Open your project in Codex.
- Copy and paste the prompt below.
- Review files and risks before approving any action.
Inspect the Agent Skill at https://github.com/RConsortium/S7/blob/HEAD/.claude/skills/property-dots/SKILL.md and all supporting files. Report provenance, permissions, scripts, dependencies, and security risks. Propose an exact installation into .agents/skills/property-dots, but wait for my approval before writing files or running scripts.
Copying this prompt does not install or run the skill. Review third-party files before use.
Accept properties via ...
Use this skill when writing a new function that collects property name-value pairs
through ..., e.g. new_object(`_parent`, ...) or set_props(`_object`, ...).
Two problems show up whenever ... carries property values:
- A fixed argument can shadow a property of the same name. If
set_props()had a formal calledobject, thenset_props(x, object = 1)would bindobjectto the formal instead of treating it as the propertyobject. - Callers sometimes want to supply property values programmatically, as a
single list, rather than as individual
name = valuepairs.
collect_dots() and the underscore naming convention solve these.
For example, take (a simple version of) update_props()
update_props <- function(`_object`, ...) {
props(`_object`) <- collect_dots(...)
`_object`
}
# Both work
update_props(x, object = 1, width = 10)
update_props(x, list(object = 1, width = 10))
The underscore convention
Property names starting with _ are reserved for internal use. This lets you name a fixed argument with a leading _ so it can never collide with a real property passed through ....
new_object(`_parent`, ...)—_parentis the parent object.set_props(`_object`, ...)—_objectis the object to modify.
_parent and _object are not syntactically valid names, so they must be
backtick-quoted everywhere they appear:
set_props <- function(`_object`, ..., .check = TRUE) {
props(`_object`, check = .check) <- collect_dots(...)
`_object`
}
Because these arguments are always passed positionally (and generated
constructors pass the parent positionally), the unusual name never burdens
callers — it only stops the name from competing with ....
Apply the convention when:
- The function takes properties via
..., AND - It also needs a fixed argument that a user might plausibly use as a property
name (
object,parent,value, ...).
Collecting the dots with collect_dots()
collect_dots(...) returns a named list of the ... values. As a convenience,
if ... is a single unnamed list, its elements are used instead, which makes
it easy to build the values programmatically. It errors if any value is
unnamed.
collect_dots(x = 1, y = 2) # list(x = 1, y = 2)
collect_dots(list(x = 1, y = 2)) # list(x = 1, y = 2) -- spliced
collect_dots(1) # error: All arguments to `...` must be named.
collect_dots(list(1)) # error: All elements of `..1` must be named.
Use collect_dots() instead of list(...).
Documenting it
In the @param for ..., mention the single-list shortcut:
#' @param ... Name-value pairs of properties to set. As a convenience, you can
#' supply a single unnamed list instead of individual name-value pairs, which
#' makes it easy to set properties programmatically.
roxygen handles @param _object and a backtick-quoted formal fine.