Skip to content

value has no way to specify which dictionaries to resolve symbols in, which an embedding API would need #4605

Description

@d-torrance

This issue was triaged from bugs/dan/1-value-dictionary-path, one of the 857 files removed from the pre-GitHub bugs/ tree by d2c8d27826 and catalogued in #36. The commentary below was written by Claude (Claude Opus 5, via Claude Code), not by @d-torrance, whose account posted it -- please weigh it accordingly.

The original file, verbatim

What's needed is a version of "value" that accepts a dictionary path to use for
looking up symbols in.

Where it stands today

value resolves symbols against the ambient dictionaryPath and offers no way to override that for a
single call. methods value has eight entries — String, Nothing, IndexedVariableTable,
IndexedVariable, RingElement, Pseudocode, Expression, Symbol — and none takes a dictionary or
a list of them.

The only workaround is the one M2 cannot unwind

old = dictionaryPath;
dictionaryPath = {...};
value s;                    -- if this raises, the next line never runs
dictionaryPath = old;

M2 has no unwind-protect. pushvar/popvar (Core.m2:67-73) is the closest thing and does not restore
on error either — pushing a value and then raising leaves the value changed and the stack unbalanced,
and Core.m2:65 carries -- TODO: move to the interpreter and make thread-safe.

At the top level this is survivable: you notice, and you fix your session.

Where it stops being survivable

The request is worth more as a foundation than as a convenience, and the case that makes it concrete is
embedding M2 in a host program.

  • A host cannot unwind the assignment. From C there is no try to wrap the call in, so an M2 error
    during value leaves dictionaryPath permanently altered with no opportunity to restore it.
  • One global path cannot serve several evaluation contexts. A process serving multiple independent
    sessions — which is the shape of Macaulay2Web — has no way to say "evaluate this string in that
    session's namespace".
  • New symbols need a destination. value "x = 3" puts x somewhere; a host wants to say where,
    and today the answer is wherever the global path happens to point.

A per-call argument is the standard answer to all three, and it is the kind of primitive that is much
cheaper to add before an embedding API is designed around its absence than after.

The notion already exists in the language

localDictionaries returns the dictionaries belonging to a function's own scope, and code.m2:20 uses
it — so "these dictionaries, for this purpose" is already expressible. What is missing is handing such a
list to value.

Shape

Something like value(String, List), or an option, taking the dictionaries to resolve against. The
signature is worth deciding alongside whatever an embedding API would want rather than in isolation;
the point of filing is that the gap exists and has a consumer in view.

Related

#1427 asks that loadPackage not scribble in the user's
dictionary — the same concern about namespace containment, from the other direction.
#917 and
#1627 are the other open dictionary-hygiene issues.

open · disposition issue · source of truth: bug-triage/catalog.tsv

Metadata

Metadata

Assignees

No one assigned

    Labels

    CoreIssues involving the Core scripts.bugs directoryConverted from a file in the old `bugs` directoryfeature request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions