Skip to content

ui.Provider methods take variadic arguments #699

Closed as not planned
Closed as not planned

Description

@David-Noble-at-work

Feature: #698 · Epic: #445 · Plan: docs/plans/ui-at-root.md

All six ui.Provider methods take a single msg string:

func (p *Provider) Error(msg string)
func (p *Provider) Fail(msg string) error
func (p *Provider) Note(msg string)
func (p *Provider) Print(msg string)
func (p *Provider) Succeed(msg string)
func (p *Provider) Warn(msg string)

Make them variadic. This is worth doing on its own merits — note("saw", n, "packages") is the natural
way to write it — and it is a hard prerequisite for #698, because the builtin print these methods are
about to replace is variadic.

The contract to match

starlark-go's print (starlark/library.go:799):

  • variadic over positional arguments
  • sep keyword, defaulting to " "
  • strings written as-is; Bytes written raw; everything else through writeValue, i.e. its repr
  • returns None

Variadic provider methods already work — file.Join(parts ...string) is announced today — so the
signature change needs no bridge work.

Steps

  1. (args ...any) on all six; Fail(args ...any) error
  2. Join the way the builtin does: strings as-is, everything else through the value's Starlark representation
  3. Decide sep — a matching keyword parameter, or a documented narrowing. The bridge has a
    kwargs map[string]any convention (flow.Degraded uses it), so it is available if we want it
  4. Update the method table in docs/architecture/3.5.16-ui-provider.md and its status companion
  5. Regenerate; confirm all six still claim deterministic, so a hermetic planning runtime keeps its output

Verification

  • ui.note("a", 1, True) renders each argument the way Starlark would
  • make check, make test-race, make test-scenario
  • Claim check green across "", darwin, linux, windows

Activity

  1. David-Noble-at-work commented on Aug 26, 2026

    @David-Noble-at-work
    ContributorAuthor

    Correction to step 3, after reading the generator.

    goast marks a parameter variadic with variadic := isLast && isEllipsis (cmd/star/provider/goast/helpers.go:438). Go requires ... to be last, so nothing can follow the variadic parameter — there is no signature that is both Go-variadic and carries a sep keyword.

    The bridge's kwargs sink does not rescue it: it must be last too, and a non-final []any is not marked variadic by that rule. That is why flow.Degraded's args []any is an ordinary list parameter, not a variadic sink.

    So step 3 is a fork, not a preference:

    1. Drop sep — Print(args ...any), joined with " "
    2. sep first — inverts the ergonomics, makes print("a") bind to the separator. Rejected
    3. Teach goast a declared variadic sink so Print(args []any, sep string) is expressible — generator and bridge work, for one keyword

    Sweep result: zero sep= call sites across every .star file in the tree. Recommending 1.

  2. David-Noble-at-work commented on Aug 26, 2026

    @David-Noble-at-work
    ContributorAuthor

    Settled: no sep keyword.

    Print(args ...any), joined with " ". Zero sep= call sites in the tree, so the narrowing costs nothing, and option 3 (teaching goast a declared variadic sink) stays available if the need ever appears.

    Rationale from the ruling: sep has always been dumb.

  3. David-Noble-at-work commented on Aug 26, 2026

    @David-Noble-at-work
    ContributorAuthor

    Closing: no signature changes. ui.Provider methods keep (msg string).

    Two candidate reconciliations with the builtin were considered and both fail:

    fmt.Printf semantics — double interpretation. Starlark's % is an operator that runs before the call, so print("%s" % name) arrives as a finished string. Printf semantics would re-scan that string for verbs, turning 50% off into 50%!o(MISSING)ff whenever the data contains a %. Go avoids this by making Print and Printf different functions; one function cannot be both. Everyday form: print("100% done") becomes a bug.

    Variadic space-join — the bridge has already destroyed the types. fillVariadicSlot runs toGoInto, so a Go-side args ...any receives Go natives: True as bool, None as nil, a list as []any. Rendering those Go-side gives true, <nil>, [a b] where Starlark says True, None, ["a"]. Faithful output would mean reimplementing writeValue on the far side of a conversion that already threw the information away.

    (msg string) is therefore correct rather than a compromise: the script renders with str() and % — Starlark's own rendering, deterministic by construction — and hands over a finished string. For a configuration language, requiring explicit str() is a feature.

    Survey of the tree confirms nothing breaks:

    Call sites Multi-argument Non-string argument
    print( 64 0 0
    fail( 65 0 0

    Every site passes one string, built with %, +, or an explicit str(...).

    Residual failure, named: print("a", "b") and print(42) are legal against the builtin and become errors against us. Nothing in the tree does either, but a Python reflex will produce one. The errors are legible — toGoScalar uses starlark.AsString with no coercion, so print(42) reports expected string, got int. Documenting the one-string contract moved to #700.

    All remaining work is on #700.

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

Metadata

Metadata

Labels

Area:ArchitectureSystem architecture and designEpic:StarlarkSurfaceThe Starlark authoring surfacePriority:P2Scheduled, not urgenttaskImplementation work item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions