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

Update selection-declaration design doc based on mtg / issue discussion #867

Merged
merged 1 commit into from
Aug 26, 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
18 changes: 18 additions & 0 deletions exploration/selection-declaration.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ _What use-cases do we see? Ideally, quote concrete examples._
* {{...}}
```

As another example of where the selection function and formatting functions differ, consider a person object provided as a formatting input.
A `:gender` function can return the person's gender,
but a `:personName` person name formatter function formats the name.
```
.match {$person :gender}
male {{Bienvenido {$person :personName}}}
female {{Bienvenida {$person :personName}}}
other {{Le damos la bienvenida {$person :personName}}}
Comment on lines +143 to +149
Copy link
Member

@aphillips aphillips Aug 23, 2024

Choose a reason for hiding this comment

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

This might be clearer if we show separate annotation?

.input {$person :personName}
.match {$person :gender}
male {{Does {$person} print 'male' or the person's name?}}
* {{This example is the same as use case 6}}

... or is that not your intention?

Copy link
Collaborator

@mihnita mihnita Aug 23, 2024

Choose a reason for hiding this comment

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

I don't find this to be clear.
It is in fact what we have today.

And depending on the mental model of the reader, it is unclear if the {$person} inside the message is the :gender one or the :personName one.

It is in fact what started the issue, that I can do stuff like this:

.input {$count :integer}
.match {$count :number minFractionalDigits=2}
 ...

For clarity I can imagine two options:

  1. One has a declare a .local, which gives us a different name:
.local $theName = {$person :personName}
.match {$person :gender}
male {{Does {$theName} print 'male' or the person's name?}}
* {{This example is the same as use case 6}}

OR

  1. The .match cannot have any function / parameters
.input {$person :personName}
.match {$person}
male {{Does {$person} print 'male' or the person's name?}}
* {{This example is the same as use case 6}}

Case 2 would not be useful in this case, with gender, but would be when we want consistency, in plural

Copy link
Collaborator

Choose a reason for hiding this comment

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


We already decided for immutability in .local and .input
WDYT about thinking of .match also as some kind of immutable?

These would be the rules:

if .match on $foo has any function / attributes / options on it
    if there was a .local $foo = {...} or .input {$foo ...} before
        ERROR
    else
        $foo is "bound" to the function / attributes / options in .match for the rest of the message
        // This gives us consistency between the :number selection / formatting
else
    if there was a .local $foo = {...} or .input {$foo ...} before, with a function on it
        use that exact definition ("binding") to do the selection // What we do today
    else
        ERROR, because the items on which we select must always have a function
        // So that we know what we select on, what keys might be valid, etc.
        // This is something we agreed a long time ago, useful for both linting, L10N tools, and human translators

Copy link
Collaborator

@mihnita mihnita Aug 23, 2024

Choose a reason for hiding this comment

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

Exercising the idea above:


.input {$person :name}
.match {$person :gender}

=> ERROR.
$person is "bound" to two different types / transforms / functions
Or .match tries to change an immutable .input, if you want to think of it in terms of immutability


.local $personName = {$person :name}
.match {$person :gender}
   .... {Here we can use both {$personName} and {$person} (second one kind of useless, but clear) }

=> CORRECT
We have two "variables", personName and person, no conflicts, everything is clear


.match {$count :number minFractionalDigits=2}
   .... {Here we can use {$count} and it means it is formatted as described in .match, good}

CORRECT


.input {$count :number minFractionalDigits=2}
.match {$count}
   .... {Here we can use {$count} and it means it is formatted as described in .match, good}

CORRECT


.input {$count :number minFractionalDigits=2}
.match {$count :number}
   .... {Here we can use {$count} and it means it is formatted as described in .match, good}

ERROR
Even if the function name is the same, it is still confusing.
Is .match {$count :number} inheriting the options from .input or not?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

My intention is to highlight that selection and formatting may require different functions. My example accomplishes that straightforwardly without getting into tangential questions about function composition, tradeoffs of concision vs. simplicity, etc.

I was initially confused by your example, even though it's more concise, because it wasn't making sense to me. If .input is binding the value of the expression {$person :personName} back to $person, then we no longer have the full person object accessible to provide to the :gender function in the subsequent line performing selection: .match {$person :gender}. Am I reading that right? If so, that of course highlights the outstanding question of how we should define function composition, but that's a separate topic.

Also, the example might engender the reader to want to declare a .local person-name {$person :personName} for all the repetition in the patterns, but then if they do, they would realize that such refactoring is independent of selection. So the idea of requiring selection to take place only on variables (the design doc alternative named "Match on variables instead of expressions"), which in turn would require a .local declaration for the selector expression {$person :gender}, would not buy us anything in terms of consistency within the message because there was never a linkage between the selector expression function and pattern placeholder formatting function.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mihnita Having read your logic and explanation, it makes sense and I personally wouldn't mind this sort of conditional mutability, but as I've stated elsewhere I just see this as overly complicated and most developers are not going to invest the time to fully grasp what will happen under these different conditions, which ultimately just trades slightly increasing flexibility and conciseness for much more confusion and errors.

I think something more rigid like "selection never mutates" is incredibly clear, and barely harms the experience, if at all. You can repeat your expressions or use an input/ local.

Copy link
Member

Choose a reason for hiding this comment

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

Note that this discussion is about text that @echeran is helpfully suggesting in the design document... a document that, I'll point out, talks about all of the issues on this thread and whose point is to illustrate choices we might make to resolve the problems it raises. @echeran has answered my question, so I'm happy to merge this so that we can have the actual discussion 😄

```

## Requirements

_What properties does the solution have to manifest to enable the use-cases above?_
Expand Down Expand Up @@ -175,6 +185,7 @@ Examples:
**Pros**
- No changes required.
- `.local` can be used to solve problems with variations in selection and formatting
- No confusion or overlap of keywords' behavior (ex: `.match`, `.input`)
- Supports multiple selectors on the same operand

**Cons**
Expand Down Expand Up @@ -217,6 +228,8 @@ declaration = s variable [s] "=" [s] expression
- Produces an error when users inappropriately annotate some items

**Cons**
- Complexity: `.match` means more than one thing
- Complexity: `.match` implicitly creates a new lexical scope
- Selectors can't provide additional selection-specific options
if the variable name is already in scope
- Doesn't allow multiple selection on the same operand, e.g.
Expand Down Expand Up @@ -249,6 +262,8 @@ Instead the selector's annotation replaces what came before.
- Shorthand version works intuitively with minimal typing.

**Cons**
- Complexity: `.match` means more than one thing
- Complexity: `.match` implicitly creates a new lexical scope
- Violates immutability that we've established everywhere else

### Allow _immutable_ input declarative selectors
Expand Down Expand Up @@ -280,6 +295,8 @@ This implies that multiple selecton on the same operand is pointless.
- Produces an error when users inappropriately annotate some items

**Cons**
- Complexity: `.match` means more than one thing
- Complexity: `.match` implicitly creates a new lexical scope
- Selectors can't provide additional selection-specific options
if the value has already been annotated
- Doesn't allow multiple selection on the same operand, e.g.
Expand Down Expand Up @@ -321,6 +338,7 @@ The ABNF change would look like:
- Preserves immutability.

**Cons**
- Complicates the situations where selection != formatting due to the strictness's design nudges
- A separate declaration is required for each selector.

### Provide a `#`-like Feature
Expand Down