-
-
Notifications
You must be signed in to change notification settings - Fork 36
Clarify declaration immutability #511
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
Clarify declaration immutability #511
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought local declarations were allowed to override external variables? Or was that a rejected proposal?
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 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 <sta@malolepszy.org>
Co-authored-by: Stanisław Małolepszy <sta@malolepszy.org>
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.