-
-
Notifications
You must be signed in to change notification settings - Fork 34
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
Add a :math function, for addition and subtraction #932
Conversation
@@ -381,6 +381,69 @@ together with the resolved options' values. | |||
|
|||
The _function_ `:integer` performs selection as described in [Number Selection](#number-selection) below. | |||
|
|||
### The `:math` function | |||
|
|||
The function `:math` is a selector and formatter for matching or formatting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not a formatting function, is it? A formatting function would require all of :number
or :integer
's options, e.g. to control zero digits, separators, and the like.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As proposed, you would be able to format a :math
annotated value, so doesn't that make it a formatting function? If you need the options, you can set them in a separate declaration.
|
||
#### Selection | ||
|
||
The _function_ `:math` performs selection as described in [Number Selection](#number-selection) below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this make it clear that the selection is done after the math is performed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but it's not technically necessary, as Number Selection includes this:
When implementing
MatchSelectorKeys(resolvedSelector, keys)
whereresolvedSelector
is the resolved value of a selector andkeys
is a list of strings, numeric selectors perform as described below.
which ends up referring back to the preceding Resolved Value section, which clarifies when the modifications are done on the resolved value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following still bothers me:
If the operand of the expression is an implementation-defined numeric type,
such as the resolved value of an expression with a:number
or:integer
annotation,
it can include option values.
I think we should replace that by:
If the operand of the expression is an implementation-defined numeric type,
such as the resolved value of an expression with a:number
or:integer
annotation,
it includes their options.
I really don't think we want the following two to differ in selection behavior, formatting, etc.
.local $y = {|3| :number maximumSignificantDigits=2}
.local $x = {$y :math subtract=1}
.local $x = {|2| :number maximumSignificantDigits=2}
So I'd recommend that the resolved value of :math inherit both the 'datatype' and the options from its operand.
Co-authored-by: Addison Phillips <addison@unicode.org>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa, I must of missed this earlier. It is seriously wrong.
#### Selection | ||
|
||
The _function_ `:math` performs selection as described in [Number Selection](#number-selection) below. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see some significant problems in these formulations.
The resolved value of an expression with a
:number
function
contains an implementation-defined numerical value
of the operand of the annotated expression,
together with the resolved options' values.
If that is all the resolved value is, then there is no difference in resolved value between the following two.
.local $x1 = {$x :integer}
.local $x2 = {$x :number}
But of course there is a big difference: the resolved value of $x1 contains a :integer annotation and the resolved value of $x2 contains a :number annotation, as in:
such as the _resolved value_ of an _expression_ with a `:number` or `:integer` _annotation_,
And it has to be that way, otherwise no .local setting later on could tell the difference between them.
So I think L142 of formatting.md is insufficient:
interface MessageValue { formatToString(): string formatToX(): X // where X is an implementation-defined type getValue(): unknown resolvedOptions(): { [key: string]: MessageValue } selectKeys(keys: string[]): string[] }
It also needs do have something like: getFunctionAnnotation();
In shorthand, the resolved value needs to logically contain a triple {datatype, functionAnnotation, optionMap}. Otherwise, a subsequent .local statement using a resolved value wouldn't have enough information to know how to compose.
So let's look at the following:
The _operand_ of a number function is either an implementation-defined type or
a literal whose contents match the `number-literal` production in the [ABNF](/spec/message.abnf).
All other values produce a _Bad Operand_ error.
But the operand can also be a resolved value, which is neither a literal nor just an implementation datatype; it has additional information.
And in multiple cases in this file, we have wording like:
Resolved Value
The resolved value of an expression with a :number function contains an implementation-defined numerical value of the operand of the annotated expression, together with the resolved options' values.
Now, if somewhere we say that the resolved value of any expression with a function contains that function as an annotation, then we could get away with this shorthand (although we also need to fix the wording for options).
Otherwise, we need to say:
The resolved value of an expression with a :number function contains an implementation-defined numerical value of the operand of the annotated expression, together with the :number function annotation, and the options with their respective resolved option~'s~ values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get it.
The composition model is that functions can expose specific options, but the identity of the function itself is not passed. There is no difference between the resolved values of {$x :number}
and {$x :integer}
with regard to the receiving function: it's just a numeric type. A subsequent local declaration doesn't need to know which annotation was previously applied: the preceding function handler modified the resolved value and/or passed the relevant options to communicate what happened.
It has to be that way, because otherwise each function would need to understand what all of the other functions (including namespaced ones) "mean".
If {$x :math subtract=2}
doesn't return $x - 2
as its resolved value, :number
isn't going to know what to do.
There are places where I have actively resisted "doing harm" to the resolved value based on the annotation. That's an argument we can have. Mostly I'm concerned that we don't strip information from the resolved value because of some formatting instructions:
.input {$now :date style=medium}
.local $time = {$now :time style=short}
{{"Today is {$now} and it is {$time}" only works if :date doesn't remove the time.
I assume that is okay because immutability says that if $now is a Date object or ZonedDateTime
there is no need to convert it to just a ZonedDate and make the time midnight.}}
We could change :integer
to make the resolved value the floor value of the operand or to make it the implementation-defined integer-type casting of the operand. That doesn't break immutability because the resolved value is only exposed in a declaration. I think that's the better course than what you're proposing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I conflated too many thoughts in my message. So put on hold the notion of the function annotation (not needed for release) and I focus on just 2 issues.
- The operand for a function may also be a resolved value (which includes an optionMap). That is not the same as an implementation defined type (eg Date); a resolved value can have an implementation-defined type. Thus
OLD
The operand of a number function is either an implementation-defined type or
a literal whose contents match thenumber-literal
production in the ABNF.
All other values produce a Bad Operand error.
needs to be changed to:
NEW
The operand of a number function is either an implementation-defined type or
a literal whose contents match thenumber-literal
production in the ABNF,
or a resolved value.
All other values produce a Bad Operand error.
(with similar changes for other definitions of operand of an X function.)
- The expression "together with the resolved options' values." is not accurate. For {|3| :number roundingIncrement=5 trailingZeroDisplay=auto}, that would imply a logical result of
{operand=3, resolvedOptionValues=[5, auto]}
rather than the logical result of
{operand=3, resolvedOptionMap={roundingIncrement=5, trailingZeroDisplay=auto}}
So we need to have:
OLD
... value of the operand of the annotated expression, together with the resolved options' values.
changed to something like:
NEW
... value of the operand of the annotated expression, together with a map from options to their resolved values
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with the first item is that the resolved value might not be of the correct implementation-defined type. The current text accounts for this by not mentioning. We could say instead:
The operand of a number function is either an implementation-defined type or
a literal whose contents match thenumber-literal
production in the ABNF
(either of which can be the resolved value of a previous declaration).
All other values produce a Bad Operand error.
The second suggestion we already discussed. Saying "map" was thought too prescriptive (ditto "array", "list", etc.). I can see how one might read "options' values" to mean only the values and not the k-v pairing. We might say:
... value of the operand of the annotated expression, together with options and their resolved values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One difference between {$x :number}
and {$x :integer}
is that the resolved value of the former holds a numeric value, while the resolved value of the latter holds an integer value. Given that :integer
also strips out a pre-defined set of options if they're included in the operand, and we don't mandate that the actual type of the number values match, I don't see a reason why anything in MF2 requires the resolved values to be more identifiable from each other?
The operand for a function may also be a resolved value (which includes an optionMap). That is not the same as an implementation defined type (eg Date); a resolved value can have an implementation-defined type.
The intent with the current language is that a resolved value can be considered as "an implementation defined type". We do not require an implementation to only define a single type that it supports, so both a Date
and the resolved value of a :datetime
annotation can simultaneously fit into that definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From Addison
The problem with the first item is that the resolved value might not be of the correct implementation-defined type. The current text accounts for this by not mentioning. We could say instead:
The operand of a number function is either an implementation-defined type or
a literal whose contents match thenumber-literal
production in the ABNF
(either of which can be the resolved value of a previous declaration).
All other values produce a Bad Operand error.
Wouldn't quite work. Again, we have defined the resolved value of {|3| :number style=percent} to be NOT the same as |3| — since the resolved value includes options. I think what we could say:
(either of which can be from the resolved value of a previous declaration).
I think that is at least headed in the right direction, though not as correct as
or a resolved value with those as an operand.
The second suggestion we already discussed. Saying "map" was thought too prescriptive (ditto "array", "list", etc.). I can see how one might read "options' values" to mean only the values and not the k-v pairing. We might say:
... value of the operand of the annotated expression, together with options and their resolved values.
That sounds perfect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't quite work. Again, we have defined the resolved value of {|3| :number style=percent} to be NOT the same as |3| — since the resolved value includes options. I think what we could say:
(either of which can be from the resolved value of a previous declaration).
I think this formulation is actually counterproductive. The operand is not extracted from the resolved value. The operand includes the accumulated options (which might affect the processing of the function or which might be filtered or ignored).
I agree that the operands in the two expressions in your comments have different resolved values, but one of the differences is that {|3| :number style=percent}
's resolved value is likely to be an implementation-defined numeric type (such as Java BigInteger
or BigDecimal
) and :math
wouldn't have to parse the literal |3|
again.
In any case, my formulation does not say "from" on purpose.
The later "perfect" quote relates to the resolved value of the :math
function, which is the output of the function. My clarification moved the word 'resolved' to try to make clear that the options and their values were both resolved. But this is a different context from the operand discussion just above.
- Operand: a naked argument or a resolved value (which is...)
- Resolved value: a resolved (and possibly modified) operand plus resolved options and their resolved values
Oddly, this discussion appears to be about a stock formulation in all of our functions. Can we merge :math
and then make any changes globally? Can I get your approval on this PR? I filed #937 to track this conversation so we make any agreed changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
I really don't see how this is cleaner than the It looks very close to a Which seem cleaner as implementation, and logic, but less intuitive for a user:
As a user is not intuitive at all why would I select on |
#### Selection | ||
|
||
The _function_ `:math` performs selection as described in [Number Selection](#number-selection) below. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
Co-authored-by: Addison Phillips <addison@unicode.org>
I'm going to merge this. @mihnita (or anyone else) If you have concerns about the resulting text, please raise PRs or issues. |
|
||
#### Selection | ||
|
||
The _function_ `:math` performs selection as described in [Number Selection](#number-selection) below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following still bothers me:
If the operand of the expression is an implementation-defined numeric type,
such as the resolved value of an expression with a:number
or:integer
annotation,
it can include option values.
I think we should replace that by:
If the operand of the expression is an implementation-defined numeric type,
such as the resolved value of an expression with a:number
or:integer
annotation,
it includes their options.
I really don't think we want the following two to differ in selection behavior, formatting, etc.
.local $y = {|3| :number maximumSignificantDigits=2}
.local $x = {$y :math subtract=1}
.local $x = {|2| :number maximumSignificantDigits=2}
So I'd recommend that the resolved value of :math inherit both the 'datatype' and the options from its operand.
I commented 3 days ago, with no answer. But I would like to see how the most common use case looks like. The one in my example or (more complicated) the one in issue #701, which this PR tries to solve. For now I don't see how this is solving the problem. So yes, I DO have concerns. Unanswered. It also makes things less intuitive. Select on math is not something people do. If this proposal makes It also hijacks a very good name ( |
I commented seconds too late. Please look at my comment.
…On Fri, Nov 15, 2024 at 11:35 AM Addison Phillips ***@***.***> wrote:
Merged #932 <#932>
into main.
—
Reply to this email directly, view it on GitHub
<#932 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACJLEMGGYYMNFIYEZ5QWWBD2AZEHRAVCNFSM6AAAAABRTE2G36VHI2DSMVQWIX3LMV45UABCJFZXG5LFIV3GK3TUJZXXI2LGNFRWC5DJN5XDWMJVGMYTMNZUGA2TMOI>
.
You are receiving this because you were mentioned.Message ID:
***@***.***
com>
|
Mihai, I view :math as basically producing an altered version *of a numeric
resolved value*, and thus having the same "features" (data type and
options) as its operand. Thus using it in selection and/or formatting is
not surprising.
…On Fri, Nov 15, 2024 at 11:35 AM Mihai Nita ***@***.***> wrote:
I'm going to merge this. @mihnita <https://github.com/mihnita> (or anyone
else) If you have concerns about the resulting text, please raise PRs or
issues.
I commented 3 days ago, with no answer.
But I would like to see how the most common use case looks like. The one
in my example or (more complicated) the one in issue #701
<#701>, which this
PR tries to solve.
For now I don't see how this is solving the problem.
So yes, I DO have concerns. Unanswered.
------------------------------
It also makes things less intuitive. Select on math is not something
people do.
One would expect math to take one or more numeric values, do some
operation(s), and return some more numeric values.
Not to format, and not to select.
If this proposal makes :math format and select, it is not much different
than :integer with offset.
It also hijacks a very good name (math) that would probably be better use
later for, you know, math things?
—
Reply to this email directly, view it on GitHub
<#932 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACJLEMFHCV2WGI4QUBRHITL2AZEJTAVCNFSM6AAAAABRTE2G36VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINZZG44DMMRTGM>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
The reason it does not say "their options" is that some options are not passed through. This isn't necessarily the case for Otherwise fully agree with your observations. |
... and a second later it occurs to me to point out that |
But then what's the difference between this and :integer with offset? I still want to see an example of how this looks like for the most common use case. Just curious, why was this merged? Accident? |
Yes, I agree with :math's options not being included in its resolved
values. The numeric options that are passed through can be enumerated
explicitly OR say that all of them are currently passed through, and if and
when at some future version adds an option that shouldn't be passed
through, then an explicit mention can be made as to the exception.
(I think the latter practice is far easier to read, since the former always
forces the reader to go back to the numeric functions to see which things
are *not* passed through. Moreover, it gives the reader the confidence that
:math is basically producing an altered version *of a numeric
resolved value*, and thus having the same "features" (data type and
options) as its operand. Thus using it in selection and/or formatting is
not surprising.)
…On Fri, Nov 15, 2024 at 11:44 AM Addison Phillips ***@***.***> wrote:
... and a second later it occurs to me to point out that :math's options
are *not* passed.
—
Reply to this email directly, view it on GitHub
<#932 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACJLEMDY5VLEPAMIAXGPS6L2AZFLHAVCNFSM6AAAAABRTE2G36VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINZZHAYDINRQGY>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@mihnita I apologize. I didn't mean to overlook your comment. I merged this because I didn't see further commentary and thought we'd agreed to pursue this in the WG call. I'm trying to tie up loose ends before this coming week's call. There are three possibilities here, I think. I'm sympathetic to not making
As I said, arguments can be made for each of these. I have added this to the agenda for Monday. |
Yes, but you announced "I'm going to merge this." 52 minutes ago Mark answered 51 minutes ago, and I answered 51 minutes ago. Why even ask if there is no time allowed for answers?
I didn't see a point to comment more if a 3 days comment was unaddressed?
Can someone have some example of what the equivalent of this MF1 looks like?
Because that is what issue #701 is about. So that we know what we will discuss on Monday? |
Double selectors are needed because you need plural handling for the back part of the list (imagine Polish). Note that I'm working on a phone so the example is ugly. |
@mihnita In addition to the example given by @aphillips above, the merged text also includes this example: message-format-wg/spec/registry.md Lines 386 to 397 in b6ba4bf
|
Got you. So why can't this be done with :integer and offset? Functionality similar to MF1 is implementable without problems with Submitted 2 years ago: |
I presented some arguments originally here: #926 (comment) |
I understand and somewhat agree with
"the weirdness of having the =1 and one operate on different values."
But I think that having to use a "double selection" for the same
functionality is weirder.
I suspect that most people would have to look up some example so figure out
how to build the same functionality.
But ok, maybe "weird" is in the eyes of the beholder.
Then why not use the exact same "trick" with two selectors, both :integer?
Why do we have to invent another function just for that?
Basically replace :math with :integer in the example submitted?
Mihai
…On Fri, Nov 15, 2024, 15:57 Eemeli Aro ***@***.***> wrote:
So why can't this be done with :integer and offset?
Why do we need this math thing?
I presented some arguments originally here: #926 (comment)
<#926 (comment)>
—
Reply to this email directly, view it on GitHub
<#932 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAJ7ITUMHMDYDEVYOAIMZGL2A2C5PAVCNFSM6AAAAABRTE2G36VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIOBQGE3DAOJYGA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Fixes #701.
An alternative to #926.
Adds
:math
as a new numeric function that canadd
orsubtract
from the operand.Note that the option values are more strict than for other functions; option values beyond "digit size option" are considered errors.