Skip to content

Add note to "Function Resolution" section about function argument and result types #686

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 17 commits into from
Feb 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions spec/formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,75 @@ the following steps are taken:

The form that resolved _operand_ and _option_ values take is implementation-defined.

A _declaration_ binds the resolved value of an _expression_
Copy link
Member

Choose a reason for hiding this comment

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

Not asking for any change in the tech preview, but this will definitely need to be revised afterwards.
The whole notion of a 'resolved value' is very muddy, unless it literally means "what is bound to a variable by an expression declaration", which means it also includes selection/formatting options and their values whenever those are carried over.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

#645 is an attempt to address this. (But it could go even further.)

to a _variable_.
Thus, the result of one _function_ is potentially the _operand_
of another _function_,
or the value of one of the _options_ for another function.
For example, in
```
.input {$n :number minIntegerDigits=3}
.local $n1 = {$n :number maxFractionDigits=3}
```
the value bound to `$n` is the
resolved value used as the _operand_
of the `:number` _function_
when resolving the value of the _variable_ `$n1`.

Implementations that provide a means for defining custom functions
Copy link
Member

Choose a reason for hiding this comment

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

I agree with the sense of this. We should also note somewhere that any two functions are not required to meaningfully compose; there is no requirement or expectation that the following make a meaningful composition:

.input {$date :datetime}
.local $person = {$date :x:personname}

Copy link
Collaborator

Choose a reason for hiding this comment

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

+1 to this. I'm not sure if I was able to explain this in yesterday's call, but I definitely agree that there should be no requirement for any two functions to meaningfully compose, as you've nicely put it. This is why I've been using the term cooperative composition (although I'm happy to call it something else), i.e. the functions must be aware of each other's interface in order to meaningfully compose.

Copy link
Member

Choose a reason for hiding this comment

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

+100 although there are some different things going on here. In @macchiati's example, the types don't match. The .local declaration should emit an Invalid Expression error because $date isn't of a supported type for :x:personname (presumably).

In other cases, the types can match but the annotations might not be supported:

.input {$date :date style=long}
.local $foo = {$date :time}  // not style=long because style means "dateStyle"

For now, we should basically say something like "functions can decide what operands to support" and "functions can decide what functions or function options to support". We permit "composition" without requiring it or prohibiting it.

In the default registry we can add (in the TP period) some guidance for date/time/datetime and number functions as a guide.

Copy link
Member

Choose a reason for hiding this comment

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

Agreed.

SHOULD provide a means for function implementations
to return values that contain enough information
(e.g. a representation of
the resolved _operand_ and _option_ values
that the function was called with)
to be used as arguments to subsequent calls
to the function implementations.
For example, an implementation might define an interface that allows custom function implementation.
Such an interface SHOULD define an implementation-specific
argument type `T` and return type `U`
for implementations of functions
such that `U` can be coerced to `T`.
Implementations of a _function_ SHOULD emit an
_Invalid Expression_ error for _operands_ whose resolved value
or type is not supported.

> [!NOTE]
> The behavior of the previous example is
> currently implementation-dependent. Supposing that
> the external input variable `n` is bound to the string `"1"`,
> and that the implementation formats to a string,
> the formatted result of the following message:
>
> ```
> .input {$n :number minIntegerDigits=3}
> .local $n1 = {$n :number maxFractionDigits=3}
> {{$n1}}
> ```
>
> is currently implementation-dependent.
> Depending on whether the options are preserved
> between the resolution of the first `:number` _annotation_
> and the resolution of the second `:number` _annotation_,
> a conformant implementation
> could produce either "001.000" or "1.000"
>
> Each function **specification** MAY have
> its own rules to preserve some options in the returned structure
> and discard others.
> In instances where a function specification does not determine whether an option is preserved or discarded,
> each function **implementation** of that specification MAY have
> its own rules to preserve some options in the returned structure
> and discard others.
>
>
> [!NOTE]
> During the Technical Preview,
> feedback on how the registry describes
> the flow of _resolved values_ and _options_
> from one _function_ to another,
> and on what requirements this specification should impose,
> is highly desired.

An implementation MAY pass additional arguments to the function,
as long as reasonable precautions are taken to keep the function interface
simple and minimal, and avoid introducing potential security vulnerabilities.
Expand Down