Conversation
Having reviewed @catamorphism's previous text and looking at our current text, these are proposed **_editorial_** changes to make variable immutability clearer in the spec.
| - An _input-declaration_ MUST NOT bind a _variable_ that appears as a _variable_ in a previous | ||
| _declaration_. | ||
| - A _local-declaration_ MUST NOT bind a _variable_ that appears as a _variable_ in a previous | ||
| _declaration_. |
There was a problem hiding this comment.
I thought local declarations were allowed to override external variables? Or was that a rejected proposal?
There was a problem hiding this comment.
It's a little complicated and I should probably add text about the corner case here.
Currently you can annotate an external value using input:
#input {$var :function opt=val}
... and you can assign it to a local variable:
#local $foo = {$var :function opt=val}
... and you can overwrite an external variable so long as it is not declared:
#local $var = {$foo :function opt=val} // overwrites any `$var` passed in
But not this:
#input {$var :function opt=val}
#local $var = {$foo :something opt=val}
spec/syntax.md
Outdated
|
|
||
| > [!Note] | ||
| > These restrictions only apply to _declarations_. | ||
| > A _placeholder_ or _selector_ MAY override the annotation provided in a _declaration_. |
There was a problem hiding this comment.
I think it's very confusing to call this "overriding", since no new name is being introduced. It's just constructing a new expression.
There was a problem hiding this comment.
Fair enough. Try the wording changes in the e9908c8.
spec/syntax.md
Outdated
| > input {$var :number maxFractionDigits=0} | ||
| > match {$var :plural maxFractionDigits=2} | ||
| > when 0 {{The selector can re-annotate {$var}}} | ||
| > when * {{This pattern can re-annotate {$var :number maxFractionDigits=3}}} |
There was a problem hiding this comment.
The exposition is better, but I'm still confused about the semantics. In the scope of the input declaration (the scope where $var is defined), does $var refer to the result of applying the :number formatter to $var with the option maxFractionDigits bound to 0? Or does it just refer to whatever value was passed in for $var? If the latter is true, what's the point of applying the :number annotation in the input declaration? And if the former is true, what does it mean to apply the :number formatter to an already-formatted number (or is :number expected to check whether its argument is a raw number or a formatted number, and handle those cases differently?)
There was a problem hiding this comment.
Our specification is explicit in that it doesn't say whether the declaration is early or late binding, which I think means that it doesn't matter. Another way to say that is that the input declaration means that any reference to $var should be interpreted through the function :number and the passed options.
Maybe the word re-annotate is not right? Perhaps:
| > when * {{This pattern can re-annotate {$var :number maxFractionDigits=3}}} | |
| > input {$var :number maxFractionDigits=0} | |
| > match {$var :plural maxFractionDigits=2} | |
| > when 0 {{The selector can apply a different annotation to {$var} for the purposes of selection}} | |
| > when * {{A placeholder in a pattern can apply a different annotation to {$var :number maxFractionDigits=3}}} |
There was a problem hiding this comment.
And if the former is true, what does it mean to apply the :number formatter to an already-formatted number (or is :number expected to check whether its argument is a raw number or a formatted number, and handle those cases differently?)
We don't specify what type exactly the argument to :number should be, but we do say that (a) it should be the resolved value, and that (b) the shape of the resolved value is implementation-specific. If a "resolved value" is allowed by the implementation to be a raw value, then functions must accept such raw values as arguments, in addition to richer "formattable" data structures.
Also, note that the same situation can be reproduced without input, using multiple local declarations:
local $a = {1 :number minFractionDigits=2} // formats as 1.00
local $b = {$a :number minFractionDigits=3} // formats as 1.000
There was a problem hiding this comment.
Aside: I'm not sure if the spec is currently clear enough about the requirement to allow functions to inspect the raw value and the formatting options of their arguments. Specifically, while a function may eagerly format its operand to a string, it should (must?) also return the raw underlying value and the formatting options used for formatting, in case another function wants to extend them or use them for other logic. Consider:
local $a = {1 :number minIntegerDigits=3} // formats as 001.
local $b = {$a :number minFractionDigits=3} // formats as 001.000
// min integer digits are preserved from the previous call.
input {$item :noun case=accusative count=1}
local $colorMatchingGrammaticalNumberGenderCase = {$color :adjective accord=$item}
// :adjective inspects $item to learn about case=accusative, count=1
Should I file an issue about this?
There was a problem hiding this comment.
I think it has to work that way. I don't think "eager" evaluation is necessarily to a string. It is to a "formattable". Otherwise format-to-parts wouldn't work nor would (as you point out) later annotation. Also, selectors wouldn't work:
input {$num :number maxFactionDigits=0}
match {$num}
when one {{ won't get here because {$num} won't be the string 'one' }}
when * {{ :-( }}
What "eager" evaluations might do is copy the value and modify the copy:
input {$startDate :systemTime}
local $endDate = {$startDate :add unit=days increment=6}
spec/syntax.md
Outdated
| > input {$var :number maxFractionDigits=0} | ||
| > match {$var :plural maxFractionDigits=2} | ||
| > when 0 {{The selector can re-annotate {$var}}} | ||
| > when * {{This pattern can re-annotate {$var :number maxFractionDigits=3}}} |
There was a problem hiding this comment.
And if the former is true, what does it mean to apply the :number formatter to an already-formatted number (or is :number expected to check whether its argument is a raw number or a formatted number, and handle those cases differently?)
We don't specify what type exactly the argument to :number should be, but we do say that (a) it should be the resolved value, and that (b) the shape of the resolved value is implementation-specific. If a "resolved value" is allowed by the implementation to be a raw value, then functions must accept such raw values as arguments, in addition to richer "formattable" data structures.
Also, note that the same situation can be reproduced without input, using multiple local declarations:
local $a = {1 :number minFractionDigits=2} // formats as 1.00
local $b = {$a :number minFractionDigits=3} // formats as 1.000
Co-authored-by: Stanisław Małolepszy <[email protected]>
Co-authored-by: Stanisław Małolepszy <[email protected]>
Having reviewed @catamorphism's previous text and looking at our current text, these are proposed editorial changes to make variable immutability clearer in the spec. The previous text's "a messages is not considered valid" doesn't read as proper English. We also lack an error for this (we have one for duplicate options), so I added one.