Repository: neovim
Issue: Roadmap to Array/Dict options
Labels: needs:discussion,complexity:high,options

## Background: Evolving Plans for Array/Dict Options

One of the primary goals of #25672 was to provide a clear path to Array and Dictionary option types. Much of the initial plan has changed. At first, the plan was to add multi-type options, options that would support multiple types, and then add Array/Dict typing to array-like or dict-like string options. A discussion in Matrix chat, where the conclusion was that options should have a single, canonical type, ruled out this approach.

This decision meant that array-like or dict-like string options have to be converted into Array/Dict options internally. They would be translated to and from strings in interfaces where backwards compatibility is needed. While this approach might work, it introduces a new issues: a lack of sentinel values.

## Challenges with Backwards Compatibility and Sentinel Values

Typically, global-local options have some sort of sentinel value to indicate an unset local value, which indicates to Neovim that the global value should be used instead.

For number options (like `undolevels`), we use arbitrary values like `123456`, for boolean options (currently only `autoread`), we use `-1`, for string options we use an empty string (`""`).

It is worth noting that using empty string as a sentinel value for global-local string options leads to its own problem where we can't use a literal empty string as option value for global-local string options such as `winbar`. This manifests itself in issues such as #18660.

If we add Array/Dict options, this would mean we need a sentinel value for those options as well. An empty array or empty dict may not make much sense in that regard, because it'd mean a literal empty array or empty dict would not be usable as an option value, much like what is currently the case for string options.

## Proposed solution: Redesigning option scopes

With the option scope redesign proposed in #29314, this would change. Because redesigning option scopes would allow us to instead use a boolean flag for each scope of an option, which would simply indicate if the option value is set at that scope or not. This forgoes the need for sentinel values entirely and solves the issue for both string and future Array/Dict options. However, such a refactor is quite expensive and time-consuming to do, and introduces the risk for some breaking changes.

## Choosing a path forward

This dilemma brings us to an important crossroads, we could either:

(a) Ignore the scope refactors and just implement Array/Dict options without them while setting some arbitrary sentinel value. This is the fastest way to achieve Array/Dict options but has the highest probability of introducing future baggage in terms of backwards compatibility, as well as a host of other issues relating to not being able to set an Array/Dict option to specific values.

(b) Do the scope refactors (which, once again, is very time-consuming and has the potential for breaking changes) before adding new option types. This ensures that sentinel values are unnecessary and has the best future prospects, but requires a substantial amount of work to be done beforehand.