Skip to content

Be more specific about defining resolved values #1095

@eemeli

Description

@eemeli

Originally posted by @macchiati in #1094 (comment):

I agree that the terminology is very confusing. For example, a resolved value is not a "container" as the following implies (my bolding).

The resolved value of an expression with a :string function
contains the string value of the operand of the annotated expression,
together with its resolved locale and directionality.
None of the options set on the expression are part of the resolved value.

It is instead suggested that an RV is like the class definition given in https://github.com/unicode-org/message-format-wg/blob/1f87da0574e793972d84532b25dc950115734739/spec/formatting.md#resolved-values

While this specification does not require it, a resolved value could be implemented by requiring each function handler to return a value matching the following interface:

interface MessageValue {
  formatToString(): string
  formatToX(): X // where X is an implementation-defined type
  unwrap(): unknown
  resolvedOptions(): { [key: string]: MessageValue }
  match(key: string): boolean
  betterThan(key1: string, key2: string): boolean
  directionality(): 'LTR' | 'RTL' | 'unknown'
  isolate(): boolean
  isLiteralOptionValue(): boolean
}

But that really doesn't sit very well at all with saying "contains the string value". Instead, we'd really have to say exactly what each of the methods do. And we don't do that.

If we are going down this road, we could be more specific, and replace "While this specification does not require it, a resolved value could be implemented by requiring each function handler to return a value matching the following interface:"
by the following (we use the "logically equivalent" language at many places in Unicode):

A resolved value is logically equivalent to a value matching the following interface:

We can then just have a standard table for each method, with the 2nd column's cell describing what it does; that way we won't miss something important (like describing whether the unwrap() method produces a value (vs an error) and if so, what the value is defined to be.)

No implementation is required to use those names or functions internally, but that is a more concrete, uniform way to describe what a function does and does not do

BTW

  1. I think 'unknown' above would be much better as 'Y // where Y is an implementation-defined type'.
  2. The above also implies that resolvedOptions has exactly 1 key-value pair, whereas I think the intent is that it return a map with 0 or more key-value pairs.
  3. I find the unwrap() name and explanation to be particularly obscure.
  4. The grammar of the following sentence is a bit fuzzy:
  • The resolved value of an expression could be used as an operand or option value if calling the unwrap() method of its resolved value did not emit an error. (This requires an intermediate variable declaration.) In this use case, the resolvedOptions() method could also provide a set of option values that could be taken into account by the called function.
  • I think it is intended to be something like:
  • The resolved value of an expression can be used as an operand or option value, but only if calling the unwrap() method does not emit an error. In that case, then resolvedOptions() method provides a set of option values that can be taken into account by the called function. These option values may be a subset of those used to create the resolved value.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions