Skip to content

Clarifications to 'Resolved Values' section #1081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 30, 2025

Conversation

catamorphism
Copy link
Collaborator

I was re-reading the MessageValue example and noticed that it's easy to skip over what the last three methods are for, so I added a reference to the earlier text.

I also thought that the getValue() method could have another name, since it's confusing to think about the "value" that it returns, vs. the enclosing MessageValue. The name I thought of was getResult(), but I'm open to other suggestions. I also thought it needed a little more explanation.

@catamorphism catamorphism added the editorial Issue is non-normative label Jun 13, 2025
Copy link
Collaborator

@eemeli eemeli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind changing the accessor name, but see inline comments for a few things that need fixing.

Copy link
Member

@aphillips aphillips left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the name change could be clearer?

@@ -155,7 +156,7 @@ and different implementations MAY choose to perform different levels of resoluti
> interface MessageValue {
> formatToString(): string
> formatToX(): X // where X is an implementation-defined type
> getValue(): unknown
> getResult(): unknown
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think getResult is a bit odd, given that this is an informative illustration and it is about getting the resolved value. I'm not sure what a "result" is (one might construe it to be the result of formatting, which it emphatically isn't). I would suggest either getResolvedValue (very literal) or perhaps resolveValue (since presumably the resolved value is the result of some sort of resolving...)

(Note that resolvedOptions() just below should probably be resolveOptions() instead, if we do down this path)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that getResult() returns the return value of the function handler; the resolved value is that return value, wrapped in an object that provides methods.

getResolvedValue() doesn't seem right to me, since the resolved value is the thing implementing the MessageValue interface, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I think of MessageValue as "wrapping" something, I thought of another name, unwrap(), that returns the thing being wrapped. Let me know how that looks.

Comment on lines 175 to 177
> - Using a _variable_, the _resolved value_ of an _expression_
> could be used as an _operand_ or _option value_ if
> calling the `getValue()` method of its _resolved value_ did not emit an error.
> calling the `getResult()` method of its _resolved value_ did not emit an error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is strangely worded compared to the bullets just preceeding. I would suggest instead

Suggested change
> - Using a _variable_, the _resolved value_ of an _expression_
> could be used as an _operand_ or _option value_ if
> calling the `getValue()` method of its _resolved value_ did not emit an error.
> calling the `getResult()` method of its _resolved value_ did not emit an error.
> - A _variable in a _declaration_ could be used as an _operand_ or _option value_
> if the result of `getResult()` does not emit an error.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a slightly different rewording; let me know what you think.

Copy link
Collaborator

@eemeli eemeli left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this continues to be a non-normative example, I'm fine with unwrap() if the general sense is that it's more informative than getValue().

> 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.
> - The relationship between the _operand_ and the result of the `unwrap()` method
> is specific to each function. For example, with the built-in function `:number`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"built-in" isn't right? We call this the default function set or a default function, I think?

Also, use semantic line breaks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 3c301cb

Comment on lines 181 to 182
> - The relationship between the _operand_ and the result of the `unwrap()` method
> is specific to each function. For example, with the built-in function `:number`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the is dancing around what we're trying to say. Perhaps:

Suggested change
> - The relationship between the _operand_ and the result of the `unwrap()` method
> is specific to each function. For example, with the built-in function `:number`,
> - The `unwrap()` method does not merely return the _resolved value_
> of the _operand_.
> Instead, it returns the function-specific result of the function's operation.
> For example, the default function `:number` produces the implementation-defined
> numeric value of the operand,
> even if the original _operand_'s value were a literal.
> A different function might produce a transformed value instead.
> For example, an `:uppercase` function might produce an uppercase string in place
> of the original _operand_ value,
> or a function that extracts a field from a data structure
> might return the extracted value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See what you think about d70142f? In particular, I want to make it clear that the function handler returns a MessageValue that has an unwrap() method that returns something. This makes the text a little repetitive, but I'm open to suggestions.

Also, I know @mihnita didn't like the name unwrap(), but in the WG meeting yesterday I wasn't hearing an alternative name suggestion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... I want to make it clear that the function handler returns a MessageValue that has an unwrap() method that returns something...

The unwrap() method/function returns something unless it emits an error, unless you presume that the ctor blows up on a bad value? A late-binding implementation might not bind the resolved value until required to do so, which might be very late indeed.

The more I think of it, the more I want to bikeshed the name towards MessageValue.resolvedValue(), not because that's how you'd want to name an interface or its method but because we are consistent in calling the thing we're talking about a resolved value and the point of the example is to illustrate that concept. We don't talk about "unwrapping" anywhere. I'd go further and suggest that MessageValue is wrong because its actually an Expression interface (perhaps MessageFormatExpression for clarity).

I think we do a good job not of illustrating that the method is not just required to resolve the operand, but that it might also apply local processing to it, which could include a change in type (for typed languages/environments).

I feel like the example should maybe be made less concrete, not merely start with "you're not required to do it like this" but to be more pseudocode-like, e.g.:

For example, an implementation might require function handlers
to provide an interface similar to:

MessageExpression {
   getResolvedValue(), // unwrap if you prefer
   ... // to show we might be omitting stuff
   /* for functions that support selection 
      note that I changed to match our new text */
   Match(rv, key),
   BetterThan(rv, key1, key2),
   /* for functions that support formatting */
   formatToString(),
   formatToX(), // where X is an impl-def type, perhaps to support a formatToParts functionality
   ... // other methods needed such as `isLiteral`, `isolate`, or `directionality`
   }

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling the method "getResolvedValue" would be rather problematic, because the MessageValue (or MessageExpression in your example) itself is the resolved value. Note for example the language in :number that refer to a resolved value being able to include option values.

Unless you're suggesting that we introduce a separate abstraction layer, and expect getResolvedValue() to return an object which is wrapping a value and a bag of options? That seems unnecessarily complex for what's intended to be just an example.

It would also be misleading to call it "MessageExpression", as the same interface is also used in Literal Resolution and Variable Resolution, to determine the values of operands, options, and variant keys.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this discussion because it's the entire reason why I opened this PR :) We have a name for "resolved value", but we don't have a name for the thing inside the resolved value that is returned by unwrap()/getValue()/whatever. Because we don't have a name for it, it's easy to slip and call it the "resolved value", but the resolved value is the thing with methods on it. (At least in our example scenario.)

Instead of unwrap(), what about getInnerValue() or getOutput()? Instead of MessageValue or MessageExpression, what about getWrappedValue()? The best way I can think of what to describe what a resolved value is is that it wraps an implementation-specific value in an object with certain methods.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like the example should maybe be made less concrete, not merely start with "you're not required to do it like this" but to be more pseudocode-like, e.g.:

I like giving a complete TypeScript definition of the interface because if an implementor doesn't have strong opinions about how to represent things, they can just take that and adapt it to their implementation language. Or, what about beginning with the "pseudocode" version and ending with the complete interface?

@aphillips aphillips merged commit bbc1c01 into unicode-org:main Jun 30, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
editorial Issue is non-normative
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants