Skip to content
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

[FEEDBACK] What is the semantic difference between local declaration using itself, and an input declaration #819

Open
lucacasonato opened this issue Jul 9, 2024 · 7 comments
Labels
Preview-Feedback Feedback gathered during the technical preview

Comments

@lucacasonato
Copy link
Contributor

Consider the following message:

.input {$count :integer}
{{You have {$count} apples.}}

From my understanding this would be identical to the following message, were it allowed.

.local $count = {$count :integer}
{{You have {$count} apples.}}

I understand this is not allowed, due to the following syntax restriction:

A local-declaration MUST NOT bind a variable that appears in its expression.

This does make me wonder why we distinguish between these at all in the data model. They are objectively identical outside of syntax. It is only in the MF2 syntax that these are different.

In a potential combined data model for these two it would also trivial to tell whether a given declaration came from an input or a local declaration, due to the syntax restriction from earlier - if a declaration has the same variable on the left and the right, then it came from a .input, otherwise it came from a .local.

@lucacasonato lucacasonato added the Preview-Feedback Feedback gathered during the technical preview label Jul 9, 2024
@aphillips
Copy link
Member

This representation is not permitted because it breaks immutability. Variable values are immutable in MF2. A value can be annotated using a declaration, but the value itself cannot be changed.

A .input provides a way to annotate (but not change) a value passed in. So .input {$count :integer} says that there must be a variable count passed in (or you'd get a resolution error) and adds an annotation asking for it to be formatted/selected as an integer.

A .local provides a way to assign a new value. So .local $count = {:expression} provides a way of assigning a value to the name count. If you want to change the value of an existing value count, you have to assign it to another name, e.g. .local $count1 = {$count :something}.

This is described by the design on variable mutability

@lucacasonato
Copy link
Contributor Author

Ok, then my understanding of what .input is is wrong - I described my initial understanding in #818.

@aphillips
Copy link
Member

This example being allowed makes no sense to me then: https://messageformat.dev/playground/#LmlucHV0IHskY291bnQgOm51bWJlciBzdHlsZT1wZXJjZW50fQp7e3skbmFtZX19fQ.ewogICJuYW1lIjogMTIzCn0.ZW4tVVM

The example message is:

.input {$count :number style=percent}
{{{$name}}}

The inputs supplied include name but not count. Since the pattern does not reference $count, the message can format without triggering an error ($count is never used).

An implementation is permitted to do eager evaluation, in which case this message could cause an Unresolved Variable error. However, we have some group members who are strongly committed to lazy evaluation. Such an implementation would never detect the unresolved variable (unless we require every declaration to be evaluated, which breaks lazy evaluation).

Note that lazy or semi-lazy evaluation allows for messages to reference variables that are only sometimes passed in and to annotate those values. For example:

.input {$delivery :datetime dateStyle=long timeStyle=long}
.match {$packagesDelivered :integer}
0 {{No packages were delivered}}
one {{{$packagesDelivered} package was delivered: {$delivery}}}
* {{{$packagesDelivered} packages were delivered: {$delivery}}}

$delivery only matters if packagesDelivered != 0.

Admittedly this sort of message is rare and somewhat unusual.

@lucacasonato
Copy link
Contributor Author

Whoops - its late here. The right message and data would be: https://messageformat.dev/playground/#LmlucHV0IHskY291bnQgOm51bWJlciBzdHlsZT1wZXJjZW50fQp7e3skY291bnR9fX0.ewogICJjb3VudCI6IDEyMwp9.ZW4tVVM

.input {$count :number style=percent}
{{{$count}}}

This behaves like I had initially thought. I then do not understand why this is not identical to a theoretical:

.local $count = {$count :number style=percent}
{{{$count}}}``

At least in the data model, these are semantically equivalent.

@aphillips
Copy link
Member

Those would be semantically equivalent. We don't allow that because we have a consensus around variable immutability. See the design doc quoted elsewhere. But the data model with the change proposed in #799 would no longer care about that (there would be no data model difference). I assume you agree with the change in #799?

@lucacasonato
Copy link
Contributor Author

Yeah - that change in #799 seems very good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Preview-Feedback Feedback gathered during the technical preview
2 participants